1313
1414def _display_conflict (distribution , requirement , depth ):
1515 print (
16- "{}{}=={} # CONFLICT {}" .format (
16+ "{}{}=={} # !!! CONFLICT {}" .format (
1717 ' ' * INDENTATION * depth ,
1818 distribution .project_name ,
1919 distribution .version ,
20- requirement ,
20+ str ( requirement ) ,
2121 ),
2222 )
2323
2424
25- def _display_cyclic (distribution , requirement , depth ):
25+ def _display_cyclic (requirement , depth ):
2626 print (
27- "{}{}=={} # CYCLIC {}" .format (
27+ "{}{} # !!! CYCLIC {}" .format (
2828 ' ' * INDENTATION * depth ,
29- distribution .project_name ,
30- distribution .version ,
31- requirement ,
29+ requirement .project_name ,
30+ str (requirement ),
3231 ),
3332 )
3433
@@ -39,116 +38,104 @@ def _display_good(distribution, requirement, depth):
3938 ' ' * INDENTATION * depth ,
4039 distribution .project_name ,
4140 distribution .version ,
42- requirement ,
41+ str ( requirement ) if requirement else '' ,
4342 ),
4443 )
4544
4645
4746def _display_missing (requirement , depth ):
4847 print (
49- "{}{} # MISSING {}" .format (
48+ "{}{} # !!! MISSING {}" .format (
5049 ' ' * INDENTATION * depth ,
5150 requirement .project_name ,
52- requirement ,
51+ str ( requirement ) ,
5352 ),
5453 )
5554
5655
57- def _display_missing_reverse (requirement , depth ):
58- print (
59- "{}{} # MISSING" .format (
60- ' ' * INDENTATION * depth ,
61- requirement .project_name ,
62- ),
63- )
56+ def _display_forward (project_req ):
57+ return _display_forward_one (project_req , [])
6458
6559
66- def _display ( distributions , requirement , chain ):
60+ def _display_forward_one ( project_req , chain ):
6761 depth = len (chain )
68- try :
69- distribution = pkg_resources .get_distribution (requirement )
70- except pkg_resources .VersionConflict :
71- distribution = pkg_resources .get_distribution (requirement .key )
72- _display_conflict (distribution , requirement , depth )
73- except pkg_resources .DistributionNotFound :
74- _display_missing (requirement , depth )
75- except IndexError :
76- # https://github.com/pypa/setuptools/issues/1677
77- _display_missing (requirement , depth )
62+ project_key = project_req .key
63+ if project_key in chain :
64+ _display_cyclic (project_req , depth )
7865 else :
79- if distribution .key in chain :
80- _display_cyclic (distribution , requirement , depth )
66+ try :
67+ distribution = pkg_resources .get_distribution (project_req )
68+ except pkg_resources .DistributionNotFound :
69+ _display_missing (project_req , depth )
70+ except IndexError :
71+ # https://github.com/pypa/setuptools/issues/1677
72+ _display_missing (project_req , depth )
73+ except pkg_resources .VersionConflict :
74+ distribution = pkg_resources .get_distribution (project_key )
75+ _display_conflict (distribution , project_req , depth )
8176 else :
82- _display_good (distribution , requirement , depth )
83- try :
84- dependencies = distribution .requires (extras = requirement .extras )
85- except pkg_resources .UnknownExtra as exception :
86- print (exception )
87- else :
88- sorted_dependency_keys = sorted ([
89- dependency .key
90- for dependency
91- in dependencies
92- ])
93- all_deps = distributions [distribution .key ]['dependencies' ]
94- for dependency_key in sorted_dependency_keys :
95- dependency_requirement = all_deps [dependency_key ]
96- _display (
97- distributions ,
98- dependency_requirement ,
99- chain + [distribution .key ],
100- )
101-
102-
103- def _display_reverse (distributions , project_req , dependency_req , chain ):
77+ _display_good (distribution , project_req , depth )
78+ dependency_reqs = sorted (
79+ distribution .requires (extras = project_req .extras ),
80+ key = lambda req : req .key ,
81+ )
82+ for dependency_req in dependency_reqs :
83+ _display_forward_one (
84+ dependency_req ,
85+ chain + [distribution .key ],
86+ )
87+
88+
89+ def _display_reverse (distributions , project_requirement ):
90+ return _display_reverse_one (distributions , project_requirement , None , [])
91+
92+
93+ def _display_reverse_one (distributions , project_req , dependency_req , chain ):
10494 depth = len (chain )
105- try :
106- project_dist = pkg_resources .get_distribution (project_req )
107- except pkg_resources .DistributionNotFound :
108- _display_missing_reverse (project_req , depth )
95+ project_key = project_req .key
96+ if project_key in chain :
97+ _display_cyclic (project_req , depth )
10998 else :
110- if project_dist .key in chain :
111- _display_cyclic (project_dist , dependency_req , depth )
99+ try :
100+ distribution = pkg_resources .get_distribution (project_req )
101+ except pkg_resources .DistributionNotFound :
102+ _display_missing (project_req , depth )
112103 else :
113- if dependency_req :
114- try :
115- pkg_resources .get_distribution (dependency_req )
116- except pkg_resources .VersionConflict :
117- _display_conflict (project_dist , dependency_req , depth )
118- else :
119- _display_good (project_dist , dependency_req , depth )
120- else :
121- _display_good (project_dist , '' , depth )
122- dependents = distributions [project_dist .key ]['dependents' ]
123- for (dependent_key , dependent_req ) in sorted (dependents .items ()):
124- _display_reverse (
125- distributions ,
126- dependent_key ,
127- dependent_req ,
128- chain + [project_dist .key ],
129- )
104+ _display_good (distribution , dependency_req , depth )
105+ dependents = distributions [project_key ]['dependents' ]
106+ for (dependent_key , next_dependency_req ) in sorted (dependents .items ()):
107+ dependent_req = pkg_resources .Requirement .parse (dependent_key )
108+ _display_reverse_one (
109+ distributions ,
110+ dependent_req ,
111+ next_dependency_req ,
112+ chain + [project_key ],
113+ )
130114
131115
132116def _discover_distributions ():
133- working_set = pkg_resources .working_set
134117 distributions = {}
118+ working_set = pkg_resources .working_set
135119 for distribution in working_set : # pylint: disable=not-an-iterable
136- key = distribution .key
137- if key not in distributions :
138- distributions [ key ] = {
139- 'dependencies' : {},
120+ dist_key = distribution .key
121+ dist_val = distributions . setdefault (
122+ dist_key ,
123+ {
140124 'dependents' : {},
141- }
142- distributions [key ]['installed' ] = True
143- for requirement in distribution .requires (extras = distribution .extras ):
144- distributions [key ]['dependencies' ][requirement .key ] = requirement
145- if requirement .key not in distributions :
146- distributions [requirement .key ] = {
147- 'dependencies' : {},
125+ 'has_dependencies' : False ,
126+ },
127+ )
128+ for dependency_requirement in distribution .requires ():
129+ dep_key = dependency_requirement .key
130+ dep_val = distributions .setdefault (
131+ dep_key ,
132+ {
148133 'dependents' : {},
149- 'installed' : False ,
150- }
151- distributions [requirement .key ]['dependents' ][key ] = requirement
134+ 'has_dependencies' : False ,
135+ },
136+ )
137+ dep_val ['dependents' ][dist_key ] = dependency_requirement
138+ dist_val ['has_dependencies' ] = True
152139 return distributions
153140
154141
@@ -157,7 +144,11 @@ def _select_top_level(distributions):
157144 key
158145 for (key , info )
159146 in sorted (distributions .items ())
160- if not info ['dependents' ]
147+ if (
148+ len (info ['dependents' ]) == 0
149+ or
150+ (key in info ['dependents' ] and len (info ['dependents' ]) == 1 )
151+ )
161152 ]
162153 return selection
163154
@@ -167,25 +158,29 @@ def _select_bottom_level(distributions):
167158 key
168159 for (key , info )
169160 in sorted (distributions .items ())
170- if info [ 'installed' ] and not info ['dependencies ' ]
161+ if not info ['has_dependencies ' ]
171162 ]
172163 return selection
173164
174165
175166def main (selection , reverse ):
176167 """ Main function """
177- distributions = _discover_distributions ()
168+ distributions = None
169+ if reverse or not selection :
170+ distributions = _discover_distributions ()
171+
178172 if not selection :
179173 if reverse :
180174 selection = _select_bottom_level (distributions )
181175 else :
182176 selection = _select_top_level (distributions )
177+
183178 for item in selection :
184179 requirement = pkg_resources .Requirement .parse (item )
185180 if reverse :
186- _display_reverse (distributions , requirement , None , [] )
181+ _display_reverse (distributions , requirement )
187182 else :
188- _display ( distributions , requirement , [] )
183+ _display_forward ( requirement )
189184
190185
191186# EOF
0 commit comments