Coverage for pipxl/deptree.py: 98%
37 statements
« prev ^ index » next coverage.py v6.5.0, created at 2022-11-28 20:56 +0100
« prev ^ index » next coverage.py v6.5.0, created at 2022-11-28 20:56 +0100
1# SPDX-FileCopyrightText: 2022-present Jeroen van Zundert <mail@jeroenvanzundert.nl>
2#
3# SPDX-License-Identifier: MIT
5from __future__ import annotations
7import textwrap
8from pathlib import Path
10from pipxl.data import ReqFileEntry
11from pipxl.resolver import pip_resolve
14def deptree(files_in: list[Path] | None = None, package_spec: list[str] | None = None) -> str:
15 reqs, _ = pip_resolve(files_in, package_spec)
17 top_level = [req for req in reqs if req.requested]
19 output = ""
20 for req in top_level:
21 output += f"{req.name}=={req.version}\n"
22 output += textwrap.indent(_deps_to_string(req.requires, reqs), prefix="\t")
24 return output
27def deptreerev(files_in: list[Path] | None = None, package_spec: list[str] | None = None) -> str:
28 reqs, _ = pip_resolve(files_in, package_spec)
30 output = ""
31 for req in reqs:
32 output += f"{req.name}=={req.version}\n"
33 output += textwrap.indent(_reverse_deps_to_string(req.required_by, reqs), prefix="\t")
34 return output
37def _deps_to_string(deps: dict[str, str], reqs: list[ReqFileEntry]) -> str:
38 output = ""
39 for dep_name, dep_spec in deps.items():
40 try:
41 info = next(t for t in reqs if t.name == dep_name)
42 output += f"{dep_name}=={info.version} [{dep_spec}]\n"
43 output += textwrap.indent(_deps_to_string(info.requires, reqs), prefix="\t")
44 except StopIteration:
45 # StopIteration is raised if the dependency is not found in reqs.
46 # If a package is not in reqs, it means that it would not be installed by pip.
47 # This is usually the case for dependencies that are only required on other Python versions
48 # or platforms, but not on the specific combination this function is run.
49 continue
51 return output
54def _reverse_deps_to_string(rev_deps: dict[str, str], reqs: list[ReqFileEntry]) -> str:
55 output = ""
56 for dep_name, dep_spec in rev_deps.items():
57 info = next(t for t in reqs if t.name == dep_name) 57 ↛ exitline 57 didn't finish the generator expression on line 57
58 output += f"{dep_name}=={info.version} [{dep_spec}]\n"
59 output += textwrap.indent(_reverse_deps_to_string(info.required_by, reqs), prefix="\t")
60 return output