src/eric7/PipInterface/pipdeptree.py

Sun, 05 Mar 2023 12:26:12 +0100

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sun, 05 Mar 2023 12:26:12 +0100
branch
eric7
changeset 9849
99782ca569ed
parent 9653
e67609152c5e
child 10026
617290a049f0
permissions
-rw-r--r--

Third Party packages
- Upgraded eradicate to version 2.2.0.
- Upgraded pipdeptree to version 2.5.2.
- Upgraded pip-licenses to version 4.1.0.

9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
1 #!/usr/bin/env python
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
2 # -*- coding: utf-8 -*-
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
3
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
4 #
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
5 # eric-ide modification: Copyright from file "LICENSE"
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
6 #
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
7
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
8 """
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
9 Copyright (c) The pipdeptree developers
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
10
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
11 Permission is hereby granted, free of charge, to any person obtaining
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
12 a copy of this software and associated documentation files (the
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
13 "Software"), to deal in the Software without restriction, including
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
14 without limitation the rights to use, copy, modify, merge, publish,
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
15 distribute, sublicense, and/or sell copies of the Software, and to
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
16 permit persons to whom the Software is furnished to do so, subject to
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
17 the following conditions:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
18
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
19 The above copyright notice and this permission notice shall be
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
20 included in all copies or substantial portions of the Software.
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
21
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
22 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
23 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
24 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
25 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
26 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
27 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
28 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
29 """
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
30
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
31 #
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
32 # Slightly modified to be used within the eric-ide project.
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
33 #
9653
e67609152c5e Updated copyright for 2023.
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9589
diff changeset
34 # Copyright (c) 2022 - 2023 Detlev Offenbach <detlev@die-offenbachs.de>
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
35 #
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
36
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
37 import argparse
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
38 import inspect
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
39 import json
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
40 import os
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
41 import shutil
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
42 import subprocess
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
43 import sys
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
44 import tempfile
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
45 from collections import defaultdict, deque
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
46 from collections.abc import Mapping
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
47 from importlib import import_module
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
48 from itertools import chain
9849
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
49 from textwrap import dedent
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
50
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
51 from pip._vendor import pkg_resources
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
52
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
53 try:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
54 from pip._internal.operations.freeze import FrozenRequirement
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
55 except ImportError:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
56 from pip import FrozenRequirement
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
57
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
58
9849
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
59 __version__ = '2.5.2' # eric-ide modification: from version.py
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
60
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
61
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
62 flatten = chain.from_iterable
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
63
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
64
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
65 def sorted_tree(tree):
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
66 """
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
67 Sorts the dict representation of the tree. The root packages as well as the intermediate packages are sorted in the
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
68 alphabetical order of the package names.
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
69
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
70 :param dict tree: the pkg dependency tree obtained by calling `construct_tree` function
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
71 :returns: sorted tree
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
72 :rtype: dict
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
73 """
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
74 return {k: sorted(v) for k, v in sorted(tree.items())}
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
75
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
76
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
77 def guess_version(pkg_key, default="?"):
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
78 """Guess the version of a pkg when pip doesn't provide it
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
79
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
80 :param str pkg_key: key of the package
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
81 :param str default: default version to return if unable to find
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
82 :returns: version
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
83 :rtype: string
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
84 """
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
85 try:
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
86 if sys.version_info >= (3, 8): # pragma: >=3.8 cover
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
87 import importlib.metadata as importlib_metadata
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
88 else: # pragma: <3.8 cover
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
89 import importlib_metadata
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
90 return importlib_metadata.version(pkg_key)
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
91 except ImportError:
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
92 pass
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
93 # Avoid AssertionError with setuptools, see https://github.com/tox-dev/pipdeptree/issues/162
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
94 if pkg_key in {"setuptools"}:
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
95 return default
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
96 try:
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
97 m = import_module(pkg_key)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
98 except ImportError:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
99 return default
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
100 else:
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
101 v = getattr(m, "__version__", default)
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
102 if inspect.ismodule(v):
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
103 return getattr(v, "__version__", default)
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
104 else:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
105 return v
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
106
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
107
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
108 def frozen_req_from_dist(dist):
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
109 # The `pip._internal.metadata` modules were introduced in 21.1.1
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
110 # and the `pip._internal.operations.freeze.FrozenRequirement`
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
111 # class now expects dist to be a subclass of
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
112 # `pip._internal.metadata.BaseDistribution`, however the
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
113 # `pip._internal.utils.misc.get_installed_distributions` continues
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
114 # to return objects of type
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
115 # pip._vendor.pkg_resources.DistInfoDistribution.
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
116 #
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
117 # This is a hacky backward compatible (with older versions of pip)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
118 # fix.
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
119 try:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
120 from pip._internal import metadata
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
121 except ImportError:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
122 pass
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
123 else:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
124 dist = metadata.pkg_resources.Distribution(dist)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
125
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
126 try:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
127 return FrozenRequirement.from_dist(dist)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
128 except TypeError:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
129 return FrozenRequirement.from_dist(dist, [])
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
130
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
131
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
132 class Package:
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
133 """
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
134 Abstract class for wrappers around objects that pip returns. This class needs to be subclassed with implementations
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
135 for `render_as_root` and `render_as_branch` methods.
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
136 """
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
137
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
138 def __init__(self, obj):
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
139 self._obj = obj
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
140 self.project_name = obj.project_name
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
141 self.key = obj.key
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
142
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
143 def render_as_root(self, frozen): # noqa: U100
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
144 return NotImplementedError
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
145
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
146 def render_as_branch(self, frozen): # noqa: U100
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
147 return NotImplementedError
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
148
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
149 def render(self, parent=None, frozen=False):
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
150 if not parent:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
151 return self.render_as_root(frozen)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
152 else:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
153 return self.render_as_branch(frozen)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
154
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
155 @staticmethod
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
156 def frozen_repr(obj):
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
157 fr = frozen_req_from_dist(obj)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
158 return str(fr).strip()
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
159
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
160 def __getattr__(self, key):
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
161 return getattr(self._obj, key)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
162
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
163 def __repr__(self):
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
164 return f'<{self.__class__.__name__}("{self.key}")>'
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
165
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
166 def __lt__(self, rhs):
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
167 return self.key < rhs.key
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
168
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
169
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
170 class DistPackage(Package):
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
171 """
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
172 Wrapper class for pkg_resources.Distribution instances
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
173
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
174 :param obj: pkg_resources.Distribution to wrap over
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
175 :param req: optional ReqPackage object to associate this DistPackage with. This is useful for displaying the tree
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
176 in reverse
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
177 """
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
178
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
179 def __init__(self, obj, req=None):
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
180 super().__init__(obj)
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
181 self.version_spec = None
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
182 self.req = req
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
183
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
184 def render_as_root(self, frozen):
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
185 if not frozen:
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
186 return f"{self.project_name}=={self.version}"
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
187 else:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
188 return self.__class__.frozen_repr(self._obj)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
189
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
190 def render_as_branch(self, frozen):
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
191 assert self.req is not None
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
192 if not frozen:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
193 parent_ver_spec = self.req.version_spec
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
194 parent_str = self.req.project_name
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
195 if parent_ver_spec:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
196 parent_str += parent_ver_spec
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
197 return f"{self.project_name}=={self.version} [requires: {parent_str}]"
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
198 else:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
199 return self.render_as_root(frozen)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
200
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
201 def as_requirement(self):
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
202 """Return a ReqPackage representation of this DistPackage"""
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
203 return ReqPackage(self._obj.as_requirement(), dist=self)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
204
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
205 def as_parent_of(self, req):
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
206 """
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
207 Return a DistPackage instance associated to a requirement. This association is necessary for reversing the
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
208 PackageDAG.
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
209
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
210 If `req` is None, and the `req` attribute of the current instance is also None, then the same instance will be
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
211 returned.
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
212
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
213 :param ReqPackage req: the requirement to associate with
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
214 :returns: DistPackage instance
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
215 """
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
216 if req is None and self.req is None:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
217 return self
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
218 return self.__class__(self._obj, req)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
219
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
220 def as_dict(self):
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
221 return {"key": self.key, "package_name": self.project_name, "installed_version": self.version}
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
222
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
223
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
224 class ReqPackage(Package):
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
225 """
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
226 Wrapper class for Requirements instance
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
227
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
228 :param obj: The `Requirements` instance to wrap over
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
229 :param dist: optional `pkg_resources.Distribution` instance for this requirement
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
230 """
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
231
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
232 UNKNOWN_VERSION = "?"
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
233
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
234 def __init__(self, obj, dist=None):
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
235 super().__init__(obj)
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
236 self.dist = dist
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
237
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
238 @property
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
239 def version_spec(self):
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
240 specs = sorted(self._obj.specs, reverse=True) # `reverse` makes '>' prior to '<'
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
241 return ",".join(["".join(sp) for sp in specs]) if specs else None
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
242
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
243 @property
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
244 def installed_version(self):
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
245 if not self.dist:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
246 return guess_version(self.key, self.UNKNOWN_VERSION)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
247 return self.dist.version
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
248
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
249 @property
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
250 def is_missing(self):
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
251 return self.installed_version == self.UNKNOWN_VERSION
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
252
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
253 def is_conflicting(self):
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
254 """If installed version conflicts with required version"""
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
255 # unknown installed version is also considered conflicting
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
256 if self.installed_version == self.UNKNOWN_VERSION:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
257 return True
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
258 ver_spec = self.version_spec if self.version_spec else ""
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
259 req_version_str = f"{self.project_name}{ver_spec}"
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
260 req_obj = pkg_resources.Requirement.parse(req_version_str)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
261 return self.installed_version not in req_obj
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
262
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
263 def render_as_root(self, frozen):
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
264 if not frozen:
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
265 return f"{self.project_name}=={self.installed_version}"
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
266 elif self.dist:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
267 return self.__class__.frozen_repr(self.dist._obj)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
268 else:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
269 return self.project_name
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
270
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
271 def render_as_branch(self, frozen):
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
272 if not frozen:
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
273 req_ver = self.version_spec if self.version_spec else "Any"
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
274 return f"{self.project_name} [required: {req_ver}, installed: {self.installed_version}]"
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
275 else:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
276 return self.render_as_root(frozen)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
277
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
278 def as_dict(self):
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
279 return {
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
280 "key": self.key,
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
281 "package_name": self.project_name,
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
282 "installed_version": self.installed_version,
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
283 "required_version": self.version_spec,
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
284 }
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
285
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
286
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
287 class PackageDAG(Mapping):
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
288 """
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
289 Representation of Package dependencies as directed acyclic graph using a dict (Mapping) as the underlying
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
290 datastructure.
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
291
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
292 The nodes and their relationships (edges) are internally stored using a map as follows,
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
293
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
294 {a: [b, c],
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
295 b: [d],
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
296 c: [d, e],
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
297 d: [e],
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
298 e: [],
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
299 f: [b],
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
300 g: [e, f]}
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
301
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
302 Here, node `a` has 2 children nodes `b` and `c`. Consider edge direction from `a` -> `b` and `a` -> `c`
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
303 respectively.
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
304
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
305 A node is expected to be an instance of a subclass of `Package`. The keys are must be of class `DistPackage` and
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
306 each item in values must be of class `ReqPackage`. (See also ReversedPackageDAG where the key and value types are
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
307 interchanged).
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
308 """
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
309
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
310 @classmethod
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
311 def from_pkgs(cls, pkgs):
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
312 pkgs = [DistPackage(p) for p in pkgs]
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
313 idx = {p.key: p for p in pkgs}
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
314 m = {p: [ReqPackage(r, idx.get(r.key)) for r in p.requires()] for p in pkgs}
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
315 return cls(m)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
316
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
317 def __init__(self, m):
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
318 """Initialize the PackageDAG object
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
319
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
320 :param dict m: dict of node objects (refer class docstring)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
321 :returns: None
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
322 :rtype: NoneType
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
323
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
324 """
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
325 self._obj = m
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
326 self._index = {p.key: p for p in list(self._obj)}
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
327
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
328 def get_node_as_parent(self, node_key):
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
329 """
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
330 Get the node from the keys of the dict representing the DAG.
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
331
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
332 This method is useful if the dict representing the DAG contains different kind of objects in keys and values.
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
333 Use this method to look up a node obj as a parent (from the keys of the dict) given a node key.
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
334
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
335 :param node_key: identifier corresponding to key attr of node obj
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
336 :returns: node obj (as present in the keys of the dict)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
337 :rtype: Object
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
338 """
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
339 try:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
340 return self._index[node_key]
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
341 except KeyError:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
342 return None
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
343
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
344 def get_children(self, node_key):
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
345 """
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
346 Get child nodes for a node by its key
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
347
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
348 :param str node_key: key of the node to get children of
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
349 :returns: list of child nodes
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
350 :rtype: ReqPackage[]
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
351 """
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
352 node = self.get_node_as_parent(node_key)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
353 return self._obj[node] if node else []
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
354
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
355 def filter(self, include, exclude):
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
356 """
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
357 Filters nodes in a graph by given parameters
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
358
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
359 If a node is included, then all it's children are also included.
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
360
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
361 :param set include: set of node keys to include (or None)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
362 :param set exclude: set of node keys to exclude (or None)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
363 :returns: filtered version of the graph
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
364 :rtype: PackageDAG
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
365 """
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
366 # If neither of the filters are specified, short circuit
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
367 if include is None and exclude is None:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
368 return self
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
369
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
370 # Note: In following comparisons, we use lower cased values so
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
371 # that user may specify `key` or `project_name`. As per the
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
372 # documentation, `key` is simply
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
373 # `project_name.lower()`. Refer:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
374 # https://setuptools.readthedocs.io/en/latest/pkg_resources.html#distribution-objects
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
375 if include:
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
376 include = {s.lower() for s in include}
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
377 if exclude:
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
378 exclude = {s.lower() for s in exclude}
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
379 else:
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
380 exclude = set()
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
381
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
382 # Check for mutual exclusion of show_only and exclude sets
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
383 # after normalizing the values to lowercase
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
384 if include and exclude:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
385 assert not (include & exclude)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
386
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
387 # Traverse the graph in a depth first manner and filter the
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
388 # nodes according to `show_only` and `exclude` sets
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
389 stack = deque()
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
390 m = {}
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
391 seen = set()
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
392 for node in self._obj.keys():
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
393 if node.key in exclude:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
394 continue
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
395 if include is None or node.key in include:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
396 stack.append(node)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
397 while True:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
398 if len(stack) > 0:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
399 n = stack.pop()
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
400 cldn = [c for c in self._obj[n] if c.key not in exclude]
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
401 m[n] = cldn
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
402 seen.add(n.key)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
403 for c in cldn:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
404 if c.key not in seen:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
405 cld_node = self.get_node_as_parent(c.key)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
406 if cld_node:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
407 stack.append(cld_node)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
408 else:
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
409 # It means there's no root node corresponding to the child node i.e.
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
410 # a dependency is missing
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
411 continue
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
412 else:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
413 break
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
414
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
415 return self.__class__(m)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
416
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
417 def reverse(self):
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
418 """
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
419 Reverse the DAG, or turn it upside-down.
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
420
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
421 In other words, the directions of edges of the nodes in the DAG will be reversed.
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
422
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
423 Note that this function purely works on the nodes in the graph. This implies that to perform a combination of
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
424 filtering and reversing, the order in which `filter` and `reverse` methods should be applied is important. For
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
425 e.g., if reverse is called on a filtered graph, then only the filtered nodes and it's children will be
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
426 considered when reversing. On the other hand, if filter is called on reversed DAG, then the definition of
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
427 "child" nodes is as per the reversed DAG.
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
428
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
429 :returns: DAG in the reversed form
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
430 :rtype: ReversedPackageDAG
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
431 """
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
432 m = defaultdict(list)
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
433 child_keys = {r.key for r in chain.from_iterable(self._obj.values())}
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
434 for k, vs in self._obj.items():
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
435 for v in vs:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
436 # if v is already added to the dict, then ensure that
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
437 # we are using the same object. This check is required
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
438 # as we're using array mutation
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
439 try:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
440 node = [p for p in m.keys() if p.key == v.key][0]
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
441 except IndexError:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
442 node = v
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
443 m[node].append(k.as_parent_of(v))
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
444 if k.key not in child_keys:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
445 m[k.as_requirement()] = []
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
446 return ReversedPackageDAG(dict(m))
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
447
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
448 def sort(self):
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
449 """
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
450 Return sorted tree in which the underlying _obj dict is an dict, sorted alphabetically by the keys.
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
451
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
452 :returns: Instance of same class with dict
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
453 """
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
454 return self.__class__(sorted_tree(self._obj))
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
455
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
456 # Methods required by the abstract base class Mapping
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
457 def __getitem__(self, *args):
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
458 return self._obj.get(*args)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
459
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
460 def __iter__(self):
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
461 return self._obj.__iter__()
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
462
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
463 def __len__(self):
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
464 return len(self._obj)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
465
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
466
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
467 class ReversedPackageDAG(PackageDAG):
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
468 """Representation of Package dependencies in the reverse order.
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
469
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
470 Similar to it's super class `PackageDAG`, the underlying datastructure is a dict, but here the keys are expected to
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
471 be of type `ReqPackage` and each item in the values of type `DistPackage`.
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
472
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
473 Typically, this object will be obtained by calling `PackageDAG.reverse`.
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
474 """
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
475
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
476 def reverse(self):
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
477 """
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
478 Reverse the already reversed DAG to get the PackageDAG again
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
479
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
480 :returns: reverse of the reversed DAG
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
481 :rtype: PackageDAG
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
482 """
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
483 m = defaultdict(list)
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
484 child_keys = {r.key for r in chain.from_iterable(self._obj.values())}
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
485 for k, vs in self._obj.items():
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
486 for v in vs:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
487 try:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
488 node = [p for p in m.keys() if p.key == v.key][0]
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
489 except IndexError:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
490 node = v.as_parent_of(None)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
491 m[node].append(k)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
492 if k.key not in child_keys:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
493 m[k.dist] = []
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
494 return PackageDAG(dict(m))
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
495
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
496
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
497 def render_text(tree, list_all=True, frozen=False):
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
498 """Print tree as text on console
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
499
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
500 :param dict tree: the package tree
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
501 :param bool list_all: whether to list all the pgks at the root level or only those that are the sub-dependencies
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
502 :param bool frozen: show the names of the pkgs in the output that's favourable to pip --freeze
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
503 :returns: None
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
504
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
505 """
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
506 tree = tree.sort()
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
507 nodes = tree.keys()
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
508 branch_keys = {r.key for r in chain.from_iterable(tree.values())}
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
509 use_bullets = not frozen
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
510
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
511 if not list_all:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
512 nodes = [p for p in nodes if p.key not in branch_keys]
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
513
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
514 def aux(node, parent=None, indent=0, cur_chain=None):
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
515 cur_chain = cur_chain or []
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
516 node_str = node.render(parent, frozen)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
517 if parent:
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
518 prefix = " " * indent + ("- " if use_bullets else "")
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
519 node_str = prefix + node_str
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
520 result = [node_str]
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
521 children = [
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
522 aux(c, node, indent=indent + 2, cur_chain=cur_chain + [c.project_name])
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
523 for c in tree.get_children(node.key)
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
524 if c.project_name not in cur_chain
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
525 ]
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
526 result += list(chain.from_iterable(children))
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
527 return result
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
528
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
529 lines = chain.from_iterable([aux(p) for p in nodes])
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
530 print("\n".join(lines))
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
531
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
532
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
533 def render_json(tree, indent):
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
534 """
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
535 Converts the tree into a flat json representation.
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
536
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
537 The json repr will be a list of hashes, each hash having 2 fields:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
538 - package
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
539 - dependencies: list of dependencies
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
540
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
541 :param dict tree: dependency tree
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
542 :param int indent: no. of spaces to indent json
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
543 :returns: json representation of the tree
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
544 :rtype: str
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
545 """
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
546 tree = tree.sort()
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
547 return json.dumps(
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
548 [{"package": k.as_dict(), "dependencies": [v.as_dict() for v in vs]} for k, vs in tree.items()], indent=indent
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
549 )
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
550
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
551
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
552 def render_json_tree(tree, indent):
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
553 """
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
554 Converts the tree into a nested json representation.
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
555
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
556 The json repr will be a list of hashes, each hash having the following fields:
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
557
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
558 - package_name
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
559 - key
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
560 - required_version
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
561 - installed_version
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
562 - dependencies: list of dependencies
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
563
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
564 :param dict tree: dependency tree
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
565 :param int indent: no. of spaces to indent json
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
566 :returns: json representation of the tree
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
567 :rtype: str
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
568 """
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
569 tree = tree.sort()
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
570 branch_keys = {r.key for r in chain.from_iterable(tree.values())}
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
571 nodes = [p for p in tree.keys() if p.key not in branch_keys]
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
572
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
573 def aux(node, parent=None, cur_chain=None):
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
574 if cur_chain is None:
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
575 cur_chain = [node.project_name]
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
576
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
577 d = node.as_dict()
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
578 if parent:
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
579 d["required_version"] = node.version_spec if node.version_spec else "Any"
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
580 else:
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
581 d["required_version"] = d["installed_version"]
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
582
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
583 d["dependencies"] = [
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
584 aux(c, parent=node, cur_chain=cur_chain + [c.project_name])
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
585 for c in tree.get_children(node.key)
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
586 if c.project_name not in cur_chain
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
587 ]
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
588
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
589 return d
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
590
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
591 return json.dumps([aux(p) for p in nodes], indent=indent)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
592
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
593
9849
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
594 def render_mermaid(tree) -> str:
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
595 """Produce a Mermaid flowchart from the dependency graph.
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
596
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
597 :param dict tree: dependency graph
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
598 """
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
599 # List of reserved keywords in Mermaid that cannot be used as node names.
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
600 # See: https://github.com/mermaid-js/mermaid/issues/4182#issuecomment-1454787806
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
601 reserved_ids: set[str] = {
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
602 "C4Component",
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
603 "C4Container",
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
604 "C4Deployment",
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
605 "C4Dynamic",
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
606 "_blank",
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
607 "_parent",
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
608 "_self",
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
609 "_top",
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
610 "call",
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
611 "class",
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
612 "classDef",
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
613 "click",
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
614 "end",
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
615 "flowchart",
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
616 "flowchart-v2",
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
617 "graph",
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
618 "interpolate",
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
619 "linkStyle",
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
620 "style",
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
621 "subgraph",
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
622 }
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
623 node_ids_map: dict[str:str] = {}
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
624
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
625 def mermaid_id(key: str) -> str:
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
626 """Returns a valid Mermaid node ID from a string."""
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
627 # If we have already seen this key, return the canonical ID.
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
628 canonical_id = node_ids_map.get(key)
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
629 if canonical_id is not None:
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
630 return canonical_id
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
631 # If the key is not a reserved keyword, return it as is, and update the map.
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
632 if key not in reserved_ids:
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
633 node_ids_map[key] = key
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
634 return key
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
635 # If the key is a reserved keyword, append a number to it.
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
636 number = 0
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
637 while True:
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
638 new_id = f"{key}_{number}"
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
639 if new_id not in node_ids_map:
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
640 node_ids_map[key] = new_id
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
641 return new_id
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
642 number += 1
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
643
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
644 # Use a sets to avoid duplicate entries.
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
645 nodes: set[str] = set()
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
646 edges: set[str] = set()
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
647
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
648 for pkg, deps in tree.items():
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
649 pkg_label = f"{pkg.project_name}\\n{pkg.version}"
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
650 pkg_key = mermaid_id(pkg.key)
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
651 nodes.add(f'{pkg_key}["{pkg_label}"]')
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
652 for dep in deps:
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
653 edge_label = dep.version_spec or "any"
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
654 dep_key = mermaid_id(dep.key)
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
655 if dep.is_missing:
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
656 dep_label = f"{dep.project_name}\\n(missing)"
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
657 nodes.add(f'{dep_key}["{dep_label}"]:::missing')
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
658 edges.add(f"{pkg_key} -.-> {dep_key}")
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
659 else:
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
660 edges.add(f'{pkg_key} -- "{edge_label}" --> {dep_key}')
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
661
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
662 # Produce the Mermaid Markdown.
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
663 indent = " " * 4
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
664 output = dedent(
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
665 f"""\
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
666 flowchart TD
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
667 {indent}classDef missing stroke-dasharray: 5
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
668 """
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
669 )
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
670 # Sort the nodes and edges to make the output deterministic.
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
671 output += indent
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
672 output += f"\n{indent}".join(node for node in sorted(nodes))
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
673 output += "\n" + indent
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
674 output += f"\n{indent}".join(edge for edge in sorted(edges))
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
675 output += "\n"
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
676 return output
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
677
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
678
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
679 def dump_graphviz(tree, output_format="dot", is_reverse=False):
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
680 """Output dependency graph as one of the supported GraphViz output formats.
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
681
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
682 :param dict tree: dependency graph
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
683 :param string output_format: output format
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
684 :param bool is_reverse: reverse or not
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
685 :returns: representation of tree in the specified output format
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
686 :rtype: str or binary representation depending on the output format
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
687
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
688 """
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
689 try:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
690 from graphviz import Digraph
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
691 except ImportError:
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
692 print("graphviz is not available, but necessary for the output " "option. Please install it.", file=sys.stderr)
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
693 sys.exit(1)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
694
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
695 try:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
696 from graphviz import parameters
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
697 except ImportError:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
698 from graphviz import backend
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
699
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
700 valid_formats = backend.FORMATS
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
701 print(
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
702 "Deprecation warning! Please upgrade graphviz to version >=0.18.0 "
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
703 "Support for older versions will be removed in upcoming release",
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
704 file=sys.stderr,
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
705 )
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
706 else:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
707 valid_formats = parameters.FORMATS
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
708
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
709 if output_format not in valid_formats:
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
710 print(f"{output_format} is not a supported output format.", file=sys.stderr)
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
711 print(f"Supported formats are: {', '.join(sorted(valid_formats))}", file=sys.stderr)
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
712 sys.exit(1)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
713
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
714 graph = Digraph(format=output_format)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
715
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
716 if not is_reverse:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
717 for pkg, deps in tree.items():
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
718 pkg_label = f"{pkg.project_name}\\n{pkg.version}"
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
719 graph.node(pkg.key, label=pkg_label)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
720 for dep in deps:
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
721 edge_label = dep.version_spec or "any"
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
722 if dep.is_missing:
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
723 dep_label = f"{dep.project_name}\\n(missing)"
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
724 graph.node(dep.key, label=dep_label, style="dashed")
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
725 graph.edge(pkg.key, dep.key, style="dashed")
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
726 else:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
727 graph.edge(pkg.key, dep.key, label=edge_label)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
728 else:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
729 for dep, parents in tree.items():
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
730 dep_label = f"{dep.project_name}\\n{dep.installed_version}"
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
731 graph.node(dep.key, label=dep_label)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
732 for parent in parents:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
733 # req reference of the dep associated with this
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
734 # particular parent package
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
735 req_ref = parent.req
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
736 edge_label = req_ref.version_spec or "any"
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
737 graph.edge(dep.key, parent.key, label=edge_label)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
738
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
739 # Allow output of dot format, even if GraphViz isn't installed.
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
740 if output_format == "dot":
9849
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
741 # Emulates graphviz.dot.Dot.__iter__() to force the sorting of graph.body.
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
742 # Fixes https://github.com/tox-dev/pipdeptree/issues/188
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
743 # That way we can guarantee the output of the dot format is deterministic
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
744 # and stable.
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
745 return "".join([tuple(graph)[0]] + sorted(graph.body) + [graph._tail])
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
746
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
747 # As it's unknown if the selected output format is binary or not, try to
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
748 # decode it as UTF8 and only print it out in binary if that's not possible.
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
749 try:
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
750 return graph.pipe().decode("utf-8")
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
751 except UnicodeDecodeError:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
752 return graph.pipe()
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
753
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
754
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
755 def print_graphviz(dump_output):
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
756 """
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
757 Dump the data generated by GraphViz to stdout.
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
758
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
759 :param dump_output: The output from dump_graphviz
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
760 """
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
761 if hasattr(dump_output, "encode"):
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
762 print(dump_output)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
763 else:
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
764 with os.fdopen(sys.stdout.fileno(), "wb") as bytestream:
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
765 bytestream.write(dump_output)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
766
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
767
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
768 def conflicting_deps(tree):
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
769 """
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
770 Returns dependencies which are not present or conflict with the requirements of other packages.
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
771
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
772 e.g. will warn if pkg1 requires pkg2==2.0 and pkg2==1.0 is installed
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
773
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
774 :param tree: the requirements tree (dict)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
775 :returns: dict of DistPackage -> list of unsatisfied/unknown ReqPackage
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
776 :rtype: dict
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
777 """
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
778 conflicting = defaultdict(list)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
779 for p, rs in tree.items():
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
780 for req in rs:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
781 if req.is_conflicting():
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
782 conflicting[p].append(req)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
783 return conflicting
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
784
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
785
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
786 def render_conflicts_text(conflicts):
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
787 if conflicts:
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
788 print("Warning!!! Possibly conflicting dependencies found:", file=sys.stderr)
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
789 # Enforce alphabetical order when listing conflicts
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
790 pkgs = sorted(conflicts.keys())
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
791 for p in pkgs:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
792 pkg = p.render_as_root(False)
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
793 print(f"* {pkg}", file=sys.stderr)
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
794 for req in conflicts[p]:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
795 req_str = req.render_as_branch(False)
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
796 print(f" - {req_str}", file=sys.stderr)
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
797
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
798
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
799 def cyclic_deps(tree):
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
800 """
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
801 Return cyclic dependencies as list of tuples
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
802
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
803 :param PackageDAG tree: package tree/dag
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
804 :returns: list of tuples representing cyclic dependencies
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
805 :rtype: list
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
806 """
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
807 index = {p.key: {r.key for r in rs} for p, rs in tree.items()}
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
808 cyclic = []
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
809 for p, rs in tree.items():
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
810 for r in rs:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
811 if p.key in index.get(r.key, []):
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
812 p_as_dep_of_r = [x for x in tree.get(tree.get_node_as_parent(r.key)) if x.key == p.key][0]
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
813 cyclic.append((p, r, p_as_dep_of_r))
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
814 return cyclic
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
815
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
816
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
817 def render_cycles_text(cycles):
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
818 if cycles:
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
819 print("Warning!! Cyclic dependencies found:", file=sys.stderr)
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
820 # List in alphabetical order of the dependency that's cycling
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
821 # (2nd item in the tuple)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
822 cycles = sorted(cycles, key=lambda xs: xs[1].key)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
823 for a, b, c in cycles:
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
824 print(f"* {a.project_name} => {b.project_name} => {c.project_name}", file=sys.stderr)
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
825
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
826
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
827 def get_parser():
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
828 parser = argparse.ArgumentParser(description="Dependency tree of the installed python packages")
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
829 parser.add_argument("-v", "--version", action="version", version=f"{__version__}")
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
830 parser.add_argument("-f", "--freeze", action="store_true", help="Print names so as to write freeze files")
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
831 parser.add_argument(
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
832 "--python",
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
833 default=sys.executable,
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
834 help="Python to use to look for packages in it (default: where" " installed)",
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
835 )
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
836 parser.add_argument("-a", "--all", action="store_true", help="list all deps at top level")
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
837 parser.add_argument(
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
838 "-l",
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
839 "--local-only",
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
840 action="store_true",
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
841 help="If in a virtualenv that has global access " "do not show globally installed packages",
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
842 )
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
843 parser.add_argument("-u", "--user-only", action="store_true", help="Only show installations in the user site dir")
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
844 parser.add_argument(
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
845 "-w",
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
846 "--warn",
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
847 action="store",
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
848 dest="warn",
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
849 nargs="?",
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
850 default="suppress",
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
851 choices=("silence", "suppress", "fail"),
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
852 help=(
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
853 'Warning control. "suppress" will show warnings '
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
854 "but return 0 whether or not they are present. "
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
855 '"silence" will not show warnings at all and '
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
856 'always return 0. "fail" will show warnings and '
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
857 "return 1 if any are present. The default is "
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
858 '"suppress".'
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
859 ),
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
860 )
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
861 parser.add_argument(
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
862 "-r",
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
863 "--reverse",
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
864 action="store_true",
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
865 default=False,
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
866 help=(
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
867 "Shows the dependency tree in the reverse fashion "
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
868 "ie. the sub-dependencies are listed with the "
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
869 "list of packages that need them under them."
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
870 ),
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
871 )
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
872 parser.add_argument(
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
873 "-p",
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
874 "--packages",
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
875 help="Comma separated list of select packages to show " "in the output. If set, --all will be ignored.",
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
876 )
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
877 parser.add_argument(
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
878 "-e",
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
879 "--exclude",
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
880 help="Comma separated list of select packages to exclude " "from the output. If set, --all will be ignored.",
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
881 metavar="PACKAGES",
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
882 )
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
883 parser.add_argument(
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
884 "-j",
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
885 "--json",
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
886 action="store_true",
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
887 default=False,
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
888 help=(
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
889 "Display dependency tree as json. This will yield "
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
890 '"raw" output that may be used by external tools. '
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
891 "This option overrides all other options."
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
892 ),
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
893 )
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
894 parser.add_argument(
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
895 "--json-tree",
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
896 action="store_true",
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
897 default=False,
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
898 help=(
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
899 "Display dependency tree as json which is nested "
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
900 "the same way as the plain text output printed by default. "
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
901 "This option overrides all other options (except --json)."
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
902 ),
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
903 )
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
904 parser.add_argument(
9849
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
905 "--mermaid",
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
906 action="store_true",
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
907 default=False,
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
908 help=("Display dependency tree as a Maermaid graph. " "This option overrides all other options."),
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
909 )
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
910 parser.add_argument(
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
911 "--graph-output",
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
912 dest="output_format",
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
913 help=(
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
914 "Print a dependency graph in the specified output "
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
915 "format. Available are all formats supported by "
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
916 "GraphViz, e.g.: dot, jpeg, pdf, png, svg"
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
917 ),
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
918 )
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
919 return parser
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
920
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
921
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
922 def _get_args():
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
923 parser = get_parser()
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
924 return parser.parse_args()
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
925
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
926
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
927 def handle_non_host_target(args):
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
928 of_python = os.path.abspath(args.python)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
929 # if target is not current python re-invoke it under the actual host
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
930 if of_python != os.path.abspath(sys.executable):
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
931 # there's no way to guarantee that graphviz is available, so refuse
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
932 if args.output_format:
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
933 print("graphviz functionality is not supported when querying" " non-host python", file=sys.stderr)
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
934 raise SystemExit(1)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
935 argv = sys.argv[1:] # remove current python executable
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
936 for py_at, value in enumerate(argv):
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
937 if value == "--python":
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
938 del argv[py_at]
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
939 del argv[py_at]
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
940 elif value.startswith("--python"):
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
941 del argv[py_at]
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
942
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
943 main_file = inspect.getsourcefile(sys.modules[__name__])
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
944 with tempfile.TemporaryDirectory() as project:
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
945 dest = os.path.join(project, "pipdeptree")
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
946 shutil.copytree(os.path.dirname(main_file), dest)
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
947 # invoke from an empty folder to avoid cwd altering sys.path
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
948 env = os.environ.copy()
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
949 env["PYTHONPATH"] = project
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
950 cmd = [of_python, "-m", "pipdeptree"]
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
951 cmd.extend(argv)
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
952 return subprocess.call(cmd, cwd=project, env=env)
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
953 return None
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
954
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
955
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
956 def get_installed_distributions(local_only=False, user_only=False):
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
957 try:
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
958 from pip._internal.metadata import pkg_resources
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
959 except ImportError:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
960 # For backward compatibility with python ver. 2.7 and pip
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
961 # version 20.3.4 (the latest pip version that works with python
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
962 # version 2.7)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
963 from pip._internal.utils import misc
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
964
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
965 return misc.get_installed_distributions(local_only=local_only, user_only=user_only)
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
966 else:
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
967 dists = pkg_resources.Environment.from_paths(None).iter_installed_distributions(
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
968 local_only=local_only, skip=(), user_only=user_only
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
969 )
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
970 return [d._dist for d in dists]
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
971
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
972
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
973 def main():
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
974 args = _get_args()
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
975 result = handle_non_host_target(args)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
976 if result is not None:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
977 return result
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
978
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
979 pkgs = get_installed_distributions(local_only=args.local_only, user_only=args.user_only)
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
980
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
981 tree = PackageDAG.from_pkgs(pkgs)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
982
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
983 is_text_output = not any([args.json, args.json_tree, args.output_format])
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
984
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
985 return_code = 0
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
986
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
987 # Before any reversing or filtering, show warnings to console
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
988 # about possibly conflicting or cyclic deps if found and warnings
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
989 # are enabled (i.e. only if output is to be printed to console)
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
990 if is_text_output and args.warn != "silence":
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
991 conflicts = conflicting_deps(tree)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
992 if conflicts:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
993 render_conflicts_text(conflicts)
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
994 print("-" * 72, file=sys.stderr)
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
995
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
996 cycles = cyclic_deps(tree)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
997 if cycles:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
998 render_cycles_text(cycles)
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
999 print("-" * 72, file=sys.stderr)
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
1000
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
1001 if args.warn == "fail" and (conflicts or cycles):
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
1002 return_code = 1
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
1003
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
1004 # Reverse the tree (if applicable) before filtering, thus ensuring
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
1005 # that the filter will be applied on ReverseTree
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
1006 if args.reverse:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
1007 tree = tree.reverse()
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
1008
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
1009 show_only = set(args.packages.split(",")) if args.packages else None
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
1010 exclude = set(args.exclude.split(",")) if args.exclude else None
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
1011
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
1012 if show_only is not None or exclude is not None:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
1013 tree = tree.filter(show_only, exclude)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
1014
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
1015 if args.json:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
1016 print(render_json(tree, indent=4))
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
1017 elif args.json_tree:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
1018 print(render_json_tree(tree, indent=4))
9849
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
1019 elif args.mermaid:
99782ca569ed Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9653
diff changeset
1020 print(render_mermaid(tree))
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
1021 elif args.output_format:
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
1022 output = dump_graphviz(tree, output_format=args.output_format, is_reverse=args.reverse)
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
1023 print_graphviz(output)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
1024 else:
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
1025 render_text(tree, args.all, args.freeze)
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
1026
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
1027 return return_code
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
1028
9589
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
1029 #
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
1030 # eric-ide modification: entry point to get one self-contained script
09218eb3ae21 Third Party packages
Detlev Offenbach <detlev@die-offenbachs.de>
parents: 9218
diff changeset
1031 #
9218
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
1032
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
1033 if __name__ == '__main__':
71cf3979a6c9 pip Interface
Detlev Offenbach <detlev@die-offenbachs.de>
parents:
diff changeset
1034 sys.exit(main())

eric ide

mercurial