Perform a runtime check of the dependency versions, using the exact same syntax used by pip. The installed module version comes from the *site-packages* dir via *importlib.metadata*. Args: requirement (`str`): pip style definition, e.g., "tokenizers==0.9.4", "tqdm>=4.60", "nu
(requirement: str, hint: str | None = None)
| 46 | |
| 47 | |
| 48 | def require_version(requirement: str, hint: str | None = None) -> None: |
| 49 | """ |
| 50 | Perform a runtime check of the dependency versions, using the exact same syntax used by pip. |
| 51 | |
| 52 | The installed module version comes from the *site-packages* dir via *importlib.metadata*. |
| 53 | |
| 54 | Args: |
| 55 | requirement (`str`): pip style definition, e.g., "tokenizers==0.9.4", "tqdm>=4.60", "numpy" |
| 56 | hint (`str`, *optional*): what suggestion to print in case of requirements not being met |
| 57 | |
| 58 | Example: |
| 59 | |
| 60 | ```python |
| 61 | require_version("pandas>1.1.2") |
| 62 | require_version("numpy>1.18.5", "this is important to have for whatever reason") |
| 63 | ```""" |
| 64 | |
| 65 | hint = f"\n{hint}" if hint is not None else "" |
| 66 | |
| 67 | # non-versioned check |
| 68 | if re.match(r"^[\w_\-\d]+$", requirement): |
| 69 | pkg, op, want_ver = requirement, None, None |
| 70 | else: |
| 71 | match = re.findall(r"^([^!=<>\s]+)([\s!=<>]{1,2}.+)", requirement) |
| 72 | if not match: |
| 73 | raise ValueError( |
| 74 | "requirement needs to be in the pip package format, .e.g., package_a==1.23, or package_b>=1.23, but" |
| 75 | f" got {requirement}" |
| 76 | ) |
| 77 | pkg, want_full = match[0] |
| 78 | want_range = want_full.split(",") # there could be multiple requirements |
| 79 | wanted = {} |
| 80 | for w in want_range: |
| 81 | match = re.findall(r"^([\s!=<>]{1,2})(.+)", w) |
| 82 | if not match: |
| 83 | raise ValueError( |
| 84 | "requirement needs to be in the pip package format, .e.g., package_a==1.23, or package_b>=1.23," |
| 85 | f" but got {requirement}" |
| 86 | ) |
| 87 | op, want_ver = match[0] |
| 88 | wanted[op] = want_ver |
| 89 | if op not in ops: |
| 90 | raise ValueError(f"{requirement}: need one of {list(ops.keys())}, but got {op}") |
| 91 | |
| 92 | # special case |
| 93 | if pkg == "python": |
| 94 | got_ver = ".".join([str(x) for x in sys.version_info[:3]]) |
| 95 | for op, want_ver in wanted.items(): |
| 96 | _compare_versions(op, got_ver, want_ver, requirement, pkg, hint) |
| 97 | return |
| 98 | |
| 99 | # check if any version is installed |
| 100 | try: |
| 101 | got_ver = importlib.metadata.version(pkg) |
| 102 | except importlib.metadata.PackageNotFoundError: |
| 103 | raise importlib.metadata.PackageNotFoundError( |
| 104 | f"The '{requirement}' distribution was not found and is required by this application. {hint}" |
| 105 | ) |