Skip to content

Commit

Permalink
Merge branch 'release-0.0.5'
Browse files Browse the repository at this point in the history
  • Loading branch information
sinoroc committed Nov 8, 2019
2 parents b1f71d6 + b542816 commit 46f1caf
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 95 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@

.. Keep the current version number on line number 5
0.0.5
=====

2019-11-08

* Rewrite implementation


0.0.4
=====

Expand Down
10 changes: 10 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,15 @@ Source code
* https://github.com/sinoroc/deptree


Details
=======

Similar projects
----------------

* `pipdeptree`_


Hacking
=======

Expand Down Expand Up @@ -91,6 +100,7 @@ Outside of a Python virtual environment run the following command::
.. Links
.. _`GNU Make`: https://www.gnu.org/software/make/
.. _`pipdeptree`: https://pypi.org/project/pipdeptree/
.. _`pytest`: https://pytest.org/
.. _`tox`: https://tox.readthedocs.io/

Expand Down
185 changes: 90 additions & 95 deletions src/deptree/_pkg_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,21 @@

def _display_conflict(distribution, requirement, depth):
print(
"{}{}=={} # CONFLICT {}".format(
"{}{}=={} # !!! CONFLICT {}".format(
' ' * INDENTATION * depth,
distribution.project_name,
distribution.version,
requirement,
str(requirement),
),
)


def _display_cyclic(distribution, requirement, depth):
def _display_cyclic(requirement, depth):
print(
"{}{}=={} # CYCLIC {}".format(
"{}{} # !!! CYCLIC {}".format(
' ' * INDENTATION * depth,
distribution.project_name,
distribution.version,
requirement,
requirement.project_name,
str(requirement),
),
)

Expand All @@ -39,116 +38,104 @@ def _display_good(distribution, requirement, depth):
' ' * INDENTATION * depth,
distribution.project_name,
distribution.version,
requirement,
str(requirement) if requirement else '',
),
)


def _display_missing(requirement, depth):
print(
"{}{} # MISSING {}".format(
"{}{} # !!! MISSING {}".format(
' ' * INDENTATION * depth,
requirement.project_name,
requirement,
str(requirement),
),
)


def _display_missing_reverse(requirement, depth):
print(
"{}{} # MISSING".format(
' ' * INDENTATION * depth,
requirement.project_name,
),
)
def _display_forward(project_req):
return _display_forward_one(project_req, [])


def _display(distributions, requirement, chain):
def _display_forward_one(project_req, chain):
depth = len(chain)
try:
distribution = pkg_resources.get_distribution(requirement)
except pkg_resources.VersionConflict:
distribution = pkg_resources.get_distribution(requirement.key)
_display_conflict(distribution, requirement, depth)
except pkg_resources.DistributionNotFound:
_display_missing(requirement, depth)
except IndexError:
# https://github.com/pypa/setuptools/issues/1677
_display_missing(requirement, depth)
project_key = project_req.key
if project_key in chain:
_display_cyclic(project_req, depth)
else:
if distribution.key in chain:
_display_cyclic(distribution, requirement, depth)
try:
distribution = pkg_resources.get_distribution(project_req)
except pkg_resources.DistributionNotFound:
_display_missing(project_req, depth)
except IndexError:
# https://github.com/pypa/setuptools/issues/1677
_display_missing(project_req, depth)
except pkg_resources.VersionConflict:
distribution = pkg_resources.get_distribution(project_key)
_display_conflict(distribution, project_req, depth)
else:
_display_good(distribution, requirement, depth)
try:
dependencies = distribution.requires(extras=requirement.extras)
except pkg_resources.UnknownExtra as exception:
print(exception)
else:
sorted_dependency_keys = sorted([
dependency.key
for dependency
in dependencies
])
all_deps = distributions[distribution.key]['dependencies']
for dependency_key in sorted_dependency_keys:
dependency_requirement = all_deps[dependency_key]
_display(
distributions,
dependency_requirement,
chain + [distribution.key],
)


def _display_reverse(distributions, project_req, dependency_req, chain):
_display_good(distribution, project_req, depth)
dependency_reqs = sorted(
distribution.requires(extras=project_req.extras),
key=lambda req: req.key,
)
for dependency_req in dependency_reqs:
_display_forward_one(
dependency_req,
chain + [distribution.key],
)


def _display_reverse(distributions, project_requirement):
return _display_reverse_one(distributions, project_requirement, None, [])


def _display_reverse_one(distributions, project_req, dependency_req, chain):
depth = len(chain)
try:
project_dist = pkg_resources.get_distribution(project_req)
except pkg_resources.DistributionNotFound:
_display_missing_reverse(project_req, depth)
project_key = project_req.key
if project_key in chain:
_display_cyclic(project_req, depth)
else:
if project_dist.key in chain:
_display_cyclic(project_dist, dependency_req, depth)
try:
distribution = pkg_resources.get_distribution(project_req)
except pkg_resources.DistributionNotFound:
_display_missing(project_req, depth)
else:
if dependency_req:
try:
pkg_resources.get_distribution(dependency_req)
except pkg_resources.VersionConflict:
_display_conflict(project_dist, dependency_req, depth)
else:
_display_good(project_dist, dependency_req, depth)
else:
_display_good(project_dist, '', depth)
dependents = distributions[project_dist.key]['dependents']
for (dependent_key, dependent_req) in sorted(dependents.items()):
_display_reverse(
distributions,
dependent_key,
dependent_req,
chain + [project_dist.key],
)
_display_good(distribution, dependency_req, depth)
dependents = distributions[project_key]['dependents']
for (dependent_key, next_dependency_req) in sorted(dependents.items()):
dependent_req = pkg_resources.Requirement.parse(dependent_key)
_display_reverse_one(
distributions,
dependent_req,
next_dependency_req,
chain + [project_key],
)


def _discover_distributions():
working_set = pkg_resources.working_set
distributions = {}
working_set = pkg_resources.working_set
for distribution in working_set: # pylint: disable=not-an-iterable
key = distribution.key
if key not in distributions:
distributions[key] = {
'dependencies': {},
dist_key = distribution.key
dist_val = distributions.setdefault(
dist_key,
{
'dependents': {},
}
distributions[key]['installed'] = True
for requirement in distribution.requires(extras=distribution.extras):
distributions[key]['dependencies'][requirement.key] = requirement
if requirement.key not in distributions:
distributions[requirement.key] = {
'dependencies': {},
'has_dependencies': False,
},
)
for dependency_requirement in distribution.requires():
dep_key = dependency_requirement.key
dep_val = distributions.setdefault(
dep_key,
{
'dependents': {},
'installed': False,
}
distributions[requirement.key]['dependents'][key] = requirement
'has_dependencies': False,
},
)
dep_val['dependents'][dist_key] = dependency_requirement
dist_val['has_dependencies'] = True
return distributions


Expand All @@ -157,7 +144,11 @@ def _select_top_level(distributions):
key
for (key, info)
in sorted(distributions.items())
if not info['dependents']
if (
len(info['dependents']) == 0
or
(key in info['dependents'] and len(info['dependents']) == 1)
)
]
return selection

Expand All @@ -167,25 +158,29 @@ def _select_bottom_level(distributions):
key
for (key, info)
in sorted(distributions.items())
if info['installed'] and not info['dependencies']
if not info['has_dependencies']
]
return selection


def main(selection, reverse):
""" Main function """
distributions = _discover_distributions()
distributions = None
if reverse or not selection:
distributions = _discover_distributions()

if not selection:
if reverse:
selection = _select_bottom_level(distributions)
else:
selection = _select_top_level(distributions)

for item in selection:
requirement = pkg_resources.Requirement.parse(item)
if reverse:
_display_reverse(distributions, requirement, None, [])
_display_reverse(distributions, requirement)
else:
_display(distributions, requirement, [])
_display_forward(requirement)


# EOF

0 comments on commit 46f1caf

Please sign in to comment.