"""Licence ontology. A licence is identified by its SPDX id when one exists (`Apache-2.0`, `MIT`, `CC-BY-NC-4.0`) and by a stable AI Atlas key otherwise (`llama-3.1-community`, `gemma-terms`, `openrail-m`). Every entry states, as booleans (or `None` when the text is ambiguous), what the licence permits — so the UI can say "commercial use allowed / derivatives allowed / redistribution allowed / acceptable-use restrictions" instead of the meaningless "open source" for a model whose weights merely download. `normalize_license(raw)` maps the strings observed in the wild (Hugging Face `license:` tags, docs pages, GitHub) to a canonical key. Unknown strings return `None` — the raw label is kept separately by the writer (`license_raw`); nothing is guessed. """ from __future__ import annotations import re from dataclasses import dataclass, field # Categories are about *what the text allows*, not about ideology. CATEGORIES = ("permissive", "copyleft", "creative-commons", "responsible-ai", "community", "research-only", "proprietary", "unknown") @dataclass(frozen=True) class LicenseInfo: key: str # canonical key (SPDX id when applicable) label: str # display name category: str # one of CATEGORIES spdx: str | None = None # SPDX identifier when the licence is in the SPDX list url: str | None = None # canonical text commercial_use: bool | None = None # may be used commercially redistribution: bool | None = None # weights/code may be redistributed derivatives: bool | None = None # fine-tunes / modifications allowed hosting_restrictions: bool | None = None # restrictions on hosting the model as a service for third parties (incl. MAU caps) attribution: bool | None = None # attribution / notice required acceptable_use: bool | None = None # an acceptable-use policy restricts what the model may do osi_approved: bool = False # OSI-approved open-source licence (code) — never true for custom model licences weights_downloadable: bool = True # False for proprietary API-only terms aliases: tuple[str, ...] = field(default_factory=tuple) def as_dict(self) -> dict[str, object]: return { "key": self.key, "label": self.label, "category": self.category, "spdx": self.spdx, "url": self.url, "commercial_use": self.commercial_use, "redistribution": self.redistribution, "derivatives": self.derivatives, "hosting_restrictions": self.hosting_restrictions, "attribution": self.attribution, "acceptable_use": self.acceptable_use, "osi_approved": self.osi_approved, "weights_downloadable": self.weights_downloadable, } def _permissive(key: str, label: str, spdx: str, url: str, **kw: object) -> LicenseInfo: base: dict[str, object] = dict(key=key, label=label, category="permissive", spdx=spdx, url=url, commercial_use=True, redistribution=True, derivatives=True, hosting_restrictions=False, attribution=True, acceptable_use=False, osi_approved=True) base.update(kw) return LicenseInfo(**base) # type: ignore[arg-type] LICENSES: dict[str, LicenseInfo] = {} def _add(info: LicenseInfo) -> None: LICENSES[info.key] = info # ---------------------------------------------------------------------------------------------- permissive / copyleft (OSI) _add(_permissive("Apache-2.0", "Apache License 2.0", "Apache-2.0", "https://www.apache.org/licenses/LICENSE-2.0", aliases=("apache 2.0", "apache-2", "apache2", "apache license 2.0", "apache license, version 2.0", "apache", "apache license", "apache software license", "apache software license 2.0", "asl 2.0", "asl-2.0"))) _add(_permissive("MIT", "MIT License", "MIT", "https://opensource.org/license/mit", aliases=("mit license", "the mit license"))) _add(LicenseInfo(key="MIT-Modified", label="Modified MIT License", category="permissive", spdx=None, commercial_use=True, redistribution=True, derivatives=True, hosting_restrictions=None, attribution=True, acceptable_use=None, aliases=("modified mit", "mit-modified"))) _add(_permissive("BSD-3-Clause", "BSD 3-Clause License", "BSD-3-Clause", "https://opensource.org/license/bsd-3-clause", aliases=("bsd-3", "bsd 3-clause", "bsd3", "new bsd", "modified bsd", "bsd", "bsd license", "bsd-3-clause license"))) _add(_permissive("BSD-2-Clause", "BSD 2-Clause License", "BSD-2-Clause", "https://opensource.org/license/bsd-2-clause", aliases=("bsd-2", "simplified bsd"))) _add(_permissive("ISC", "ISC License", "ISC", "https://opensource.org/license/isc-license-txt")) _add(_permissive("Unlicense", "The Unlicense", "Unlicense", "https://unlicense.org", attribution=False, aliases=("unlicense",))) _add(_permissive("0BSD", "Zero-Clause BSD", "0BSD", "https://opensource.org/license/0bsd", attribution=False)) _add(LicenseInfo(key="GPL-3.0", label="GNU GPL v3", category="copyleft", spdx="GPL-3.0-only", url="https://www.gnu.org/licenses/gpl-3.0.html", commercial_use=True, redistribution=True, derivatives=True, hosting_restrictions=False, attribution=True, acceptable_use=False, osi_approved=True, aliases=("gpl-3.0-only", "gpl-3.0-or-later", "gplv3", "gpl3", "gpl-3"))) _add(LicenseInfo(key="GPL-2.0", label="GNU GPL v2", category="copyleft", spdx="GPL-2.0-only", url="https://www.gnu.org/licenses/old-licenses/gpl-2.0.html", commercial_use=True, redistribution=True, derivatives=True, hosting_restrictions=False, attribution=True, acceptable_use=False, osi_approved=True, aliases=("gpl-2.0-only", "gpl-2.0-or-later", "gplv2", "gpl2", "gpl-2"))) _add(LicenseInfo(key="LGPL-3.0", label="GNU LGPL v3", category="copyleft", spdx="LGPL-3.0-only", url="https://www.gnu.org/licenses/lgpl-3.0.html", commercial_use=True, redistribution=True, derivatives=True, hosting_restrictions=False, attribution=True, acceptable_use=False, osi_approved=True, aliases=("lgpl-3.0-only", "lgpl-3.0-or-later", "lgplv3", "lgpl"))) _add(LicenseInfo(key="AGPL-3.0", label="GNU AGPL v3", category="copyleft", spdx="AGPL-3.0-only", url="https://www.gnu.org/licenses/agpl-3.0.html", commercial_use=True, redistribution=True, derivatives=True, hosting_restrictions=True, attribution=True, acceptable_use=False, osi_approved=True, aliases=("agpl-3.0-only", "agpl-3.0-or-later", "agplv3", "agpl"))) _add(LicenseInfo(key="MPL-2.0", label="Mozilla Public License 2.0", category="copyleft", spdx="MPL-2.0", url="https://www.mozilla.org/MPL/2.0/", commercial_use=True, redistribution=True, derivatives=True, hosting_restrictions=False, attribution=True, acceptable_use=False, osi_approved=True, aliases=("mpl", "mozilla public license 2.0"))) _add(LicenseInfo(key="EPL-2.0", label="Eclipse Public License 2.0", category="copyleft", spdx="EPL-2.0", url="https://www.eclipse.org/legal/epl-2.0/", commercial_use=True, redistribution=True, derivatives=True, hosting_restrictions=False, attribution=True, acceptable_use=False, osi_approved=True)) # ---------------------------------------------------------------------------------------------- Creative Commons def _cc(key: str, label: str, url: str, *, nc: bool, nd: bool, sa: bool, aliases: tuple[str, ...]) -> LicenseInfo: return LicenseInfo(key=key, label=label, category="creative-commons", spdx=key, url=url, commercial_use=not nc, redistribution=True, derivatives=not nd, hosting_restrictions=nc or None, attribution=True, acceptable_use=False, osi_approved=False, aliases=aliases) _add(_cc("CC-BY-4.0", "Creative Commons Attribution 4.0", "https://creativecommons.org/licenses/by/4.0/", nc=False, nd=False, sa=False, aliases=("cc by 4.0", "cc-by", "cc by", "cc-by-4", "creative commons attribution 4.0"))) _add(_cc("CC-BY-SA-4.0", "Creative Commons Attribution-ShareAlike 4.0", "https://creativecommons.org/licenses/by-sa/4.0/", nc=False, nd=False, sa=True, aliases=("cc by-sa 4.0", "cc-by-sa", "cc by-sa"))) _add(_cc("CC-BY-NC-4.0", "Creative Commons Attribution-NonCommercial 4.0", "https://creativecommons.org/licenses/by-nc/4.0/", nc=True, nd=False, sa=False, aliases=("cc by-nc 4.0", "cc-by-nc", "cc by-nc", "cc-by-nc-4", "creative commons attribution non commercial 4.0"))) _add(_cc("CC-BY-NC-SA-4.0", "Creative Commons Attribution-NonCommercial-ShareAlike 4.0", "https://creativecommons.org/licenses/by-nc-sa/4.0/", nc=True, nd=False, sa=True, aliases=("cc by-nc-sa 4.0", "cc-by-nc-sa", "cc by-nc-sa"))) _add(_cc("CC-BY-NC-ND-4.0", "Creative Commons Attribution-NonCommercial-NoDerivatives 4.0", "https://creativecommons.org/licenses/by-nc-nd/4.0/", nc=True, nd=True, sa=False, aliases=("cc by-nc-nd 4.0", "cc-by-nc-nd"))) _add(_cc("CC-BY-ND-4.0", "Creative Commons Attribution-NoDerivatives 4.0", "https://creativecommons.org/licenses/by-nd/4.0/", nc=False, nd=True, sa=False, aliases=("cc by-nd 4.0", "cc-by-nd"))) _add(LicenseInfo(key="CC0-1.0", label="Creative Commons Zero 1.0 (public domain dedication)", category="creative-commons", spdx="CC0-1.0", url="https://creativecommons.org/publicdomain/zero/1.0/", commercial_use=True, redistribution=True, derivatives=True, hosting_restrictions=False, attribution=False, acceptable_use=False, aliases=("cc0", "cc0 1.0", "public domain"))) _add(LicenseInfo(key="ODC-By-1.0", label="Open Data Commons Attribution", category="creative-commons", spdx="ODC-By-1.0", url="https://opendatacommons.org/licenses/by/1-0/", commercial_use=True, redistribution=True, derivatives=True, hosting_restrictions=False, attribution=True, acceptable_use=False, aliases=("odc-by",))) _add(LicenseInfo(key="PDDL-1.0", label="Open Data Commons Public Domain Dedication", category="creative-commons", spdx="PDDL-1.0", url="https://opendatacommons.org/licenses/pddl/", commercial_use=True, redistribution=True, derivatives=True, hosting_restrictions=False, attribution=False, acceptable_use=False, aliases=("pddl",))) # ---------------------------------------------------------------------------------------------- responsible-AI (RAIL) family def _rail(key: str, label: str, url: str, aliases: tuple[str, ...]) -> LicenseInfo: return LicenseInfo(key=key, label=label, category="responsible-ai", spdx=None, url=url, commercial_use=True, redistribution=True, derivatives=True, hosting_restrictions=False, attribution=True, acceptable_use=True, osi_approved=False, aliases=aliases) _add(_rail("OpenRAIL-M", "Open RAIL-M", "https://www.licenses.ai/ai-licenses", ("openrail", "openrail-m", "open rail-m", "creativeml-openrail-m", "creativeml openrail-m"))) _add(_rail("OpenRAIL++-M", "Open RAIL++-M (Stable Diffusion XL)", "https://huggingface.co/stabilityai/stable-diffusion-xl-base-1.0/blob/main/LICENSE.md", ("openrail++", "openrail++-m"))) _add(_rail("BigScience-BLOOM-RAIL-1.0", "BigScience BLOOM RAIL 1.0", "https://huggingface.co/spaces/bigscience/license", ("bigscience-bloom-rail-1.0", "bloom-rail", "bigscience-openrail-m"))) _add(_rail("BigCode-OpenRAIL-M", "BigCode Open RAIL-M", "https://www.bigcode-project.org/docs/pages/bigcode-openrail/", ("bigcode-openrail-m",))) # ---------------------------------------------------------------------------------------------- community / custom model licences (weights download, restrictions apply) def _community(key: str, label: str, url: str, aliases: tuple[str, ...], *, commercial: bool | None = True, hosting: bool | None = True, derivatives: bool | None = True, aup: bool | None = True) -> LicenseInfo: return LicenseInfo(key=key, label=label, category="community", spdx=None, url=url, commercial_use=commercial, redistribution=True, derivatives=derivatives, hosting_restrictions=hosting, attribution=True, acceptable_use=aup, osi_approved=False, aliases=aliases) _add(_community("Llama-2-Community", "Llama 2 Community License", "https://ai.meta.com/llama/license/", ("llama2", "llama-2", "llama 2 community license", "llama2 community license"))) _add(_community("Llama-3-Community", "Llama 3 Community License", "https://llama.meta.com/llama3/license/", ("llama3", "llama-3", "llama 3 community license", "meta llama 3 community license"))) _add(_community("Llama-3.1-Community", "Llama 3.1 Community License", "https://llama.meta.com/llama3_1/license/", ("llama3.1", "llama-3.1", "llama 3.1 community license"))) _add(_community("Llama-3.2-Community", "Llama 3.2 Community License", "https://www.llama.com/llama3_2/license/", ("llama3.2", "llama-3.2", "llama 3.2 community license"))) _add(_community("Llama-3.3-Community", "Llama 3.3 Community License", "https://www.llama.com/llama3_3/license/", ("llama3.3", "llama-3.3", "llama 3.3 community license"))) _add(_community("Llama-4-Community", "Llama 4 Community License", "https://www.llama.com/llama4/license/", ("llama4", "llama-4", "llama 4 community license"))) _add(_community("Gemma-Terms", "Gemma Terms of Use", "https://ai.google.dev/gemma/terms", ("gemma", "gemma terms of use", "gemma license", "gemma-terms"))) _add(_community("Mistral-Research", "Mistral AI Research License", "https://mistral.ai/licenses/MRL-0.1.md", ("mrl", "mistral research license", "mistral ai research license", "mrl-0.1"), commercial=False, hosting=True, aup=True)) _add(_community("Mistral-Non-Production", "Mistral AI Non-Production License", "https://mistral.ai/licenses/MNPL-0.1.md", ("mnpl", "mnpl-0.1", "mistral ai non-production license"), commercial=False, hosting=True, aup=True)) _add(_community("Qwen-Research", "Qwen Research License", "https://huggingface.co/Qwen/Qwen2.5-3B/blob/main/LICENSE", ("qwen research license", "qwen-research"), commercial=False)) _add(_community("Tongyi-Qianwen", "Tongyi Qianwen License", "https://github.com/QwenLM/Qwen/blob/main/Tongyi%20Qianwen%20LICENSE%20AGREEMENT", ("tongyi-qianwen", "tongyi qianwen license", "qianwen"), commercial=True, hosting=True)) _add(_community("DeepSeek-Model", "DeepSeek Model License", "https://github.com/deepseek-ai/DeepSeek-LLM/blob/main/LICENSE-MODEL", ("deepseek", "deepseek license", "deepseek model license"), hosting=False)) _add(_community("NVIDIA-Open-Model", "NVIDIA Open Model License", "https://www.nvidia.com/en-us/agreements/enterprise-software/nvidia-open-model-license/", ("nvidia open model license", "nvidia-open-model-license", "nvidia open model"), hosting=False)) _add(_community("NVIDIA-Community-Model", "NVIDIA Community Model License", "https://www.nvidia.com/en-us/agreements/enterprise-software/nvidia-community-models-license/", ("nvidia community model license", "nvidia-community-model-license"), hosting=None)) _add(_community("Apple-AMLR", "Apple Sample Code / ML Research License", "https://github.com/apple/ml-fastvlm/blob/main/LICENSE_MODEL", ("apple-amlr", "apple-ascl", "apple ml research license"), commercial=False, hosting=True, derivatives=True)) _add(_community("Cohere-CC-BY-NC", "Cohere Labs Acceptable Use (CC-BY-NC)", "https://cohere.com/c4ai-cc-by-nc-license", ("cohere", "c4ai", "cc-by-nc-4.0 + acceptable use"), commercial=False)) _add(_community("Stability-Community", "Stability AI Community License", "https://stability.ai/community-license-agreement", ("stabilityai-ai-community", "stability ai community license", "stabilityai-community"), commercial=True, hosting=True)) _add(_community("Stability-Non-Commercial-Research", "Stability AI Non-Commercial Research Community License", "https://stability.ai/license", ("stabilityai-nc-research-community", "stability ai non-commercial research community"), commercial=False)) _add(_community("Falcon-LLM", "Falcon LLM License (TII)", "https://falconllm.tii.ae/falcon-terms-and-conditions.html", ("falcon-llm-license", "tii falcon license", "falcon"), hosting=None)) _add(_community("Yi", "Yi Series Models Community License", "https://github.com/01-ai/Yi/blob/main/MODEL_LICENSE_AGREEMENT.txt", ("yi-license", "yi license", "yi"), commercial=True)) _add(_community("ChatGLM", "ChatGLM / GLM Model License", "https://github.com/THUDM/ChatGLM3/blob/main/MODEL_LICENSE", ("glm-4", "chatglm", "glm license", "zhipu"), commercial=True)) _add(_community("Phi", "Microsoft Phi (MIT with terms)", "https://huggingface.co/microsoft/phi-4/blob/main/LICENSE", ("phi",), commercial=True, hosting=False)) _add(_community("LFM-Open-1.0", "LFM Open License v1.0 (Liquid AI)", "https://www.liquid.ai/lfm-license", ("lfm1.0", "lfm-1.0", "lfm open license"), commercial=True, hosting=True)) _add(_community("Jamba-Open-Model", "Jamba Open Model License (AI21)", "https://www.ai21.com/jamba-open-model-license/", ("jamba open model license", "jamba"), commercial=True)) _add(_community("Kimi-Modified-MIT", "Kimi Modified MIT License (Moonshot)", "https://huggingface.co/moonshotai/Kimi-K2-Instruct/blob/main/LICENSE", ("kimi modified mit", "moonshot modified mit"), commercial=True, hosting=True, aup=False)) _add(_community("SEED-Model", "ByteDance Seed Model License", "https://github.com/ByteDance-Seed", ("seed license", "bytedance seed"), commercial=None)) _add(_community("Hunyuan-Community", "Tencent Hunyuan Community License", "https://github.com/Tencent/Tencent-Hunyuan-Large/blob/main/License.docx", ("tencent-hunyuan-community", "hunyuan", "tencent hunyuan community license"), commercial=True, hosting=True)) _add(_community("IBM-Granite", "IBM Granite (Apache-2.0 with usage terms)", "https://www.ibm.com/granite", ("granite",), commercial=True, hosting=False, aup=True)) _add(_community("Custom-Community", "Custom community licence (see source)", "", ("custom community", "community license", "other-community"), commercial=None, hosting=None, derivatives=None, aup=None)) # ---------------------------------------------------------------------------------------------- research-only / non-commercial custom _add(LicenseInfo(key="Research-Only", label="Research / non-commercial licence (custom)", category="research-only", spdx=None, commercial_use=False, redistribution=None, derivatives=None, hosting_restrictions=True, attribution=True, acceptable_use=True, aliases=("research", "research only", "research-only", "non-commercial", "noncommercial", "academic", "academic use only", "non commercial"))) _add(LicenseInfo(key="Meta-Research", label="Meta Research License", category="research-only", spdx=None, url="https://ai.meta.com/resources/models-and-libraries/", commercial_use=False, redistribution=False, derivatives=True, hosting_restrictions=True, attribution=True, acceptable_use=True, aliases=("meta research license", "fair noncommercial research license", "fair-noncommercial"))) # ---------------------------------------------------------------------------------------------- proprietary _add(LicenseInfo(key="Proprietary", label="Proprietary (API / terms of service)", category="proprietary", spdx=None, commercial_use=None, redistribution=False, derivatives=False, hosting_restrictions=True, attribution=None, acceptable_use=True, weights_downloadable=False, aliases=("proprietary", "closed", "closed source", "commercial", "terms of service", "tos", "api terms", "license: proprietary"))) _add(LicenseInfo(key="Other", label="Other (unclassified licence)", category="unknown", spdx=None, aliases=("other", "unknown", "custom", "see model card", "license: other"))) # ---------------------------------------------------------------------------------------------- normalisation _ALIAS_INDEX: dict[str, str] = {} for _info in LICENSES.values(): _ALIAS_INDEX[_info.key.lower()] = _info.key if _info.spdx: _ALIAS_INDEX[_info.spdx.lower()] = _info.key for _a in _info.aliases: _ALIAS_INDEX[_a.lower()] = _info.key _STRIP = re.compile(r"\s+|[_]") _PATTERNS: list[tuple[re.Pattern[str], str]] = [ (re.compile(r"^apache[\s\-]*(license)?[\s\-,]*(version)?[\s\-]*2(\.0)?$", re.I), "Apache-2.0"), (re.compile(r"^llama[\s\-]*4", re.I), "Llama-4-Community"), (re.compile(r"^llama[\s\-]*3[.\-]3", re.I), "Llama-3.3-Community"), (re.compile(r"^llama[\s\-]*3[.\-]2", re.I), "Llama-3.2-Community"), (re.compile(r"^llama[\s\-]*3[.\-]1", re.I), "Llama-3.1-Community"), (re.compile(r"^(meta[\s\-]*)?llama[\s\-]*3", re.I), "Llama-3-Community"), (re.compile(r"^(meta[\s\-]*)?llama[\s\-]*2", re.I), "Llama-2-Community"), (re.compile(r"^gemma", re.I), "Gemma-Terms"), (re.compile(r"^cc[\s\-]*by[\s\-]*nc[\s\-]*sa", re.I), "CC-BY-NC-SA-4.0"), (re.compile(r"^cc[\s\-]*by[\s\-]*nc[\s\-]*nd", re.I), "CC-BY-NC-ND-4.0"), (re.compile(r"^cc[\s\-]*by[\s\-]*nc", re.I), "CC-BY-NC-4.0"), (re.compile(r"^cc[\s\-]*by[\s\-]*sa", re.I), "CC-BY-SA-4.0"), (re.compile(r"^cc[\s\-]*by[\s\-]*nd", re.I), "CC-BY-ND-4.0"), (re.compile(r"^cc[\s\-]*by", re.I), "CC-BY-4.0"), (re.compile(r"^cc0", re.I), "CC0-1.0"), (re.compile(r"^(creativeml[\s\-]*)?openrail\+\+", re.I), "OpenRAIL++-M"), (re.compile(r"^(creativeml[\s\-]*)?openrail", re.I), "OpenRAIL-M"), (re.compile(r"^bigscience", re.I), "BigScience-BLOOM-RAIL-1.0"), (re.compile(r"^bigcode", re.I), "BigCode-OpenRAIL-M"), (re.compile(r"^(gpl|gnu general public license)[\s\-]*v?3", re.I), "GPL-3.0"), (re.compile(r"^(gpl|gnu general public license)[\s\-]*v?2", re.I), "GPL-2.0"), (re.compile(r"^agpl", re.I), "AGPL-3.0"), (re.compile(r"^lgpl", re.I), "LGPL-3.0"), (re.compile(r"^bsd[\s\-]*3", re.I), "BSD-3-Clause"), (re.compile(r"^bsd[\s\-]*2", re.I), "BSD-2-Clause"), (re.compile(r"^mit\b", re.I), "MIT"), (re.compile(r"^mistral.*research", re.I), "Mistral-Research"), (re.compile(r"^mistral.*non[\s\-]*production", re.I), "Mistral-Non-Production"), (re.compile(r"^nvidia.*open.*model", re.I), "NVIDIA-Open-Model"), (re.compile(r"^nvidia.*community", re.I), "NVIDIA-Community-Model"), (re.compile(r"^deepseek", re.I), "DeepSeek-Model"), (re.compile(r"^qwen.*research", re.I), "Qwen-Research"), (re.compile(r"^tongyi", re.I), "Tongyi-Qianwen"), (re.compile(r"^stability.*(nc|non[\s\-]*commercial)", re.I), "Stability-Non-Commercial-Research"), (re.compile(r"^stability", re.I), "Stability-Community"), (re.compile(r"^apple", re.I), "Apple-AMLR"), (re.compile(r"^(tencent[\s\-]*)?hunyuan", re.I), "Hunyuan-Community"), (re.compile(r"^lfm", re.I), "LFM-Open-1.0"), (re.compile(r"^jamba", re.I), "Jamba-Open-Model"), (re.compile(r"^falcon", re.I), "Falcon-LLM"), (re.compile(r"^yi\b", re.I), "Yi"), (re.compile(r"(research|academic|non[\s\-]*commercial|noncommercial)", re.I), "Research-Only"), (re.compile(r"(proprietary|closed|terms of service)", re.I), "Proprietary"), ] def normalize_license(raw: str | None) -> str | None: """Map an observed licence label to a canonical key, or `None` when it cannot be classified (keep the raw string separately).""" if raw is None: return None s = str(raw).strip() if not s: return None low = s.lower().strip().strip(".") low = re.sub(r"^license:\s*", "", low) if low in _ALIAS_INDEX: return _ALIAS_INDEX[low] compact = _STRIP.sub("-", low).replace("--", "-") if compact in _ALIAS_INDEX: return _ALIAS_INDEX[compact] for pattern, key in _PATTERNS: if pattern.search(low): return key return None def license_info(key_or_raw: str | None) -> LicenseInfo | None: key = key_or_raw if key_or_raw in LICENSES else normalize_license(key_or_raw) return LICENSES.get(key) if key else None def license_label(key_or_raw: str | None) -> str | None: info = license_info(key_or_raw) return info.label if info else (str(key_or_raw) if key_or_raw else None) __all__ = ["CATEGORIES", "LICENSES", "LicenseInfo", "license_info", "license_label", "normalize_license"]