Created
May 12, 2023 14:57
-
-
Save a-recknagel/d0c44f81fef220d5543bfb94c52e6c0a to your computer and use it in GitHub Desktop.
w00t, switch/case does something useful
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from collections import defaultdict | |
import importlib.metadata | |
from typing import Any | |
from pprint import pp | |
from packaging.requirements import Requirement | |
from packaging.markers import Op, Value, Variable | |
def group_deps_by_extra(pkg: str) -> dict[str, list[str]]: | |
"""Query metadata of an installed package for extra-install-dependencies.""" | |
dists = importlib.metadata.metadata(pkg).get_all("Requires-Dist", []) # list of pep 508 strings | |
ret = defaultdict(list) | |
for dist in map(Requirement, dists): | |
if dist.marker is None: | |
continue | |
for marker in dist.marker._markers: | |
if (extra := get_extra(marker)) is not None: | |
ret[extra].append(dist.name) | |
return {**ret} | |
def get_extra_3_9(marker: Any) -> str | None: | |
# ugh... | |
if isinstance(marker, tuple) and len(marker) == 3: | |
var, op, val = marker | |
if ( | |
isinstance(var, Variable) | |
and isinstance(op, Op) | |
and isinstance(val, Value) | |
): | |
if var.value == "extra" and op.value == "==": | |
return val.value | |
# shorter alternatives are more bug-prone and may raise ~5 types of exceptions | |
def get_extra_3_10(marker: Any) -> str | None: | |
# a lot more readable | |
match marker: | |
case (Variable(value="extra"), Op(value="=="), Value(value=extra)): | |
return extra | |
get_extra = get_extra_3_9 # result is the same with `get_extra_3_10` | |
if __name__ == '__main__': | |
pp(group_deps_by_extra("fastapi")) # has a coupe of interesting extras |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# output with fastapi-0.95.1 | |
{'all': ['email-validator', | |
'httpx', | |
'itsdangerous', | |
'jinja2', | |
'orjson', | |
'python-multipart', | |
'pyyaml', | |
'ujson', | |
'uvicorn'], | |
'dev': ['pre-commit', 'ruff', 'uvicorn'], | |
'doc': ['mdx-include', | |
'mkdocs-markdownextradata-plugin', | |
'mkdocs-material', | |
'mkdocs', | |
'pyyaml', | |
'typer-cli', | |
'typer'], | |
'test': ['anyio', | |
'black', | |
'coverage', | |
'databases', | |
'email-validator', | |
'flask', | |
'httpx', | |
'isort', | |
'mypy', | |
'orjson', | |
'passlib', | |
'peewee', | |
'pytest', | |
'python-jose', | |
'python-multipart', | |
'pyyaml', | |
'ruff', | |
'sqlalchemy', | |
'types-orjson', | |
'types-ujson', | |
'ujson']} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment