Skip to content

Commit

Permalink
Merge branch 'release-0.0.10'
Browse files Browse the repository at this point in the history
  • Loading branch information
sinoroc committed Apr 17, 2020
2 parents bf796c9 + deaffce commit 7fbe2a2
Show file tree
Hide file tree
Showing 4 changed files with 107 additions and 4 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,19 @@

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

2020-04-17

* Improve detection of circular dependencies


0.0.9
=====

2010-04-15

* Show all dependencies (or dependents) in the flat view (instead of just 1
level deep)
* Show summary in CLI's help output
Expand Down
11 changes: 11 additions & 0 deletions CONTRIBUTING.rst
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,17 @@ Outside of a Python virtual environment run the following command::
tox --recreate -e package


Test circular dependencies
--------------------------

These projects can be used to test for circular dependencies:

* https://pypi.org/project/CircularDependencyA/
* https://pypi.org/project/CircularDependencyB/
* https://pypi.org/project/ineedyou/
* https://pypi.org/project/youneedme/


.. Links
.. _`GNU Make`: https://www.gnu.org/software/make/
Expand Down
8 changes: 8 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,14 @@ Examples
twine==3.1.1
.. code::
$ deptree CircularDependencyA
CircularDependencyA==0.0.0 # CircularDependencyA
CircularDependencyB==0.0.0 # CircularDependencyB
CircularDependencyA # !!! CIRCULAR CircularDependencyA
Installation
------------

Expand Down
82 changes: 78 additions & 4 deletions src/deptree/_pkg_resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ def _display_conflict(distribution, requirement, depth=0):
)


def _display_cyclic(distribution, requirement, depth=0):
def _display_circular(distribution, requirement, depth=0):
print(
"{}{} # !!! CYCLIC {}".format(
"{}{} # !!! CIRCULAR {}".format(
' ' * INDENTATION * depth,
distribution['project_name'],
requirement['str'],
Expand Down Expand Up @@ -88,7 +88,7 @@ def _display_forward_tree(distributions, requirement, chain):
project_key = requirement['dependency_project_key']
distribution = distributions.get(project_key, None)
if project_key in chain:
_display_cyclic(distribution, requirement, depth)
_display_circular(distribution, requirement, depth)
else:
if not distribution:
_display_unknown(project_key, requirement, depth)
Expand Down Expand Up @@ -117,7 +117,7 @@ def _display_reverse_tree(
project_key = requirement['dependent_project_key']
distribution = distributions.get(project_key, None)
if project_key in chain:
_display_cyclic(distribution, requirement, depth)
_display_circular(distribution, requirement, depth)
else:
if not distribution:
_display_unknown(project_key, requirement, depth)
Expand Down Expand Up @@ -262,6 +262,78 @@ def _select_flat(distributions, is_reverse, preselection, selection):
)


def _visit_forward(distributions, requirement, visited, chain) -> None:
distribution_key = requirement['dependency_project_key']
if distribution_key not in visited:
visited.append(distribution_key)
if distribution_key not in chain:
distribution = distributions.get(distribution_key, None)
if distribution:
for dependency_key in distribution['dependencies']:
dependency = distribution['dependencies'][dependency_key]
_visit_forward(
distributions,
dependency,
visited,
chain + [distribution_key],
)


def _visit_reverse(distributions, requirement, visited, chain) -> None:
distribution_key = requirement['dependent_project_key']
if distribution_key not in visited:
visited.append(distribution_key)
if distribution_key not in chain:
distribution = distributions.get(distribution_key, None)
if distribution:
for dependent_key in distribution['dependents']:
dependent_distribution = distributions[dependent_key]
dependencies = dependent_distribution['dependencies']
dependency_requirement = dependencies[distribution_key]
_visit_reverse(
distributions,
dependency_requirement,
visited,
chain + [distribution_key],
)


def _find_orphan_cycles(distributions, selection, is_reverse) -> None:
visited = []
for distribution_key in selection:
if is_reverse:
_visit_reverse(
distributions,
selection[distribution_key],
visited,
[],
)
else:
_visit_forward(
distributions,
selection[distribution_key],
visited,
[],
)
#
has_maybe_more_orphans = True
max_detections = 99
detections_counter = 0
while has_maybe_more_orphans and detections_counter < max_detections:
detections_counter += 1
has_maybe_more_orphans = False
for distribution_key in distributions:
if distribution_key not in visited:
requirement = _make_requirement(distribution_key, is_reverse)
selection[distribution_key] = requirement
if is_reverse:
_visit_reverse(distributions, requirement, visited, [])
else:
_visit_forward(distributions, requirement, visited, [])
has_maybe_more_orphans = True
break


def _select_bottom(distributions, selection) -> None:
for distribution_key in distributions:
if distribution_key not in selection:
Expand All @@ -270,6 +342,7 @@ def _select_bottom(distributions, selection) -> None:
selection[distribution_key] = (
_make_requirement(distribution_key, True)
)
_find_orphan_cycles(distributions, selection, True)


def _select_top(distributions, selection) -> None:
Expand All @@ -280,6 +353,7 @@ def _select_top(distributions, selection) -> None:
selection[distribution_key] = (
_make_requirement(distribution_key, False)
)
_find_orphan_cycles(distributions, selection, False)


class _SelectType(enum.Enum):
Expand Down

0 comments on commit 7fbe2a2

Please sign in to comment.