Merge pull request #14 from msabramo/master_fix_infinite_recursion
Fix infinite recursion for cyclic deps (#13)
This commit is contained in:
commit
adc549464e
|
@ -0,0 +1,21 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
# This is a small tool to create a pickle file for a set of packages for the
|
||||
# purposes of writing tests
|
||||
|
||||
import pickle
|
||||
import sys
|
||||
|
||||
import pip
|
||||
|
||||
|
||||
def main():
|
||||
default_skip = ['setuptools', 'pip', 'python', 'distribute']
|
||||
skip = default_skip + ['pipdeptree']
|
||||
pkgs = pip.get_installed_distributions(local_only=True, skip=skip)
|
||||
pickle.dump(pkgs, sys.stdout)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
|
@ -130,7 +130,10 @@ def render_tree(pkgs, pkg_index, req_map, list_all,
|
|||
non_top = set(r.key for r in flatten(req_map.values()))
|
||||
top = [p for p in pkgs if p.key not in non_top]
|
||||
|
||||
def aux(pkg, indent=0):
|
||||
def aux(pkg, indent=0, chain=None):
|
||||
if chain is None:
|
||||
chain = [pkg.project_name]
|
||||
|
||||
# In this function, pkg can either be a Distribution or
|
||||
# Requirement instance
|
||||
if indent > 0:
|
||||
|
@ -150,14 +153,31 @@ def render_tree(pkgs, pkg_index, req_map, list_all,
|
|||
# packages, eg. `testresources`, this will fail
|
||||
if pkg.key in pkg_index:
|
||||
pkg_deps = pkg_index[pkg.key].requires()
|
||||
result += list(flatten([aux(d, indent=indent+2)
|
||||
for d in pkg_deps]))
|
||||
filtered_deps = [
|
||||
aux(d, indent=indent+2, chain=chain+[d.project_name])
|
||||
for d in pkg_deps
|
||||
if d.project_name not in chain]
|
||||
result += list(flatten(filtered_deps))
|
||||
return result
|
||||
|
||||
lines = flatten([aux(p) for p in (pkgs if list_all else top)])
|
||||
return '\n'.join(lines)
|
||||
|
||||
|
||||
def cyclic_deps(pkgs, pkg_index):
|
||||
def aux(pkg, chain):
|
||||
if pkg.key in pkg_index:
|
||||
for d in pkg_index[pkg.key].requires():
|
||||
if d.project_name in chain:
|
||||
yield ' => '.join([str(p) for p in chain] + [str(d)])
|
||||
else:
|
||||
for cycle in aux(d, chain=chain+[d.project_name]):
|
||||
yield cycle
|
||||
|
||||
for cycle in flatten([aux(p, chain=[]) for p in pkgs]):
|
||||
yield cycle
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description=(
|
||||
'Dependency tree of the installed python packages'
|
||||
|
@ -200,6 +220,12 @@ def main():
|
|||
print(tmpl.format(pkg, req), file=sys.stderr)
|
||||
print('-'*72, file=sys.stderr)
|
||||
|
||||
cyclic = cyclic_deps(pkgs, pkg_index)
|
||||
if cyclic:
|
||||
print('Warning!! Cyclic dependencies found:', file=sys.stderr)
|
||||
for xs in cyclic:
|
||||
print('- {0}'.format(xs))
|
||||
|
||||
if args.freeze:
|
||||
top_pkg_str, non_top_pkg_str = top_pkg_src, non_top_pkg_src
|
||||
else:
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
(lp0
|
||||
ccopy_reg
|
||||
_reconstructor
|
||||
p1
|
||||
(cpip._vendor.pkg_resources
|
||||
Distribution
|
||||
p2
|
||||
c__builtin__
|
||||
object
|
||||
p3
|
||||
Ntp4
|
||||
Rp5
|
||||
(dp6
|
||||
S'project_name'
|
||||
p7
|
||||
S'CircularDependencyA'
|
||||
p8
|
||||
sS'precedence'
|
||||
p9
|
||||
I-1
|
||||
sS'_key'
|
||||
p10
|
||||
S'circulardependencya'
|
||||
p11
|
||||
sS'_version'
|
||||
p12
|
||||
S'0.0.0'
|
||||
p13
|
||||
sS'platform'
|
||||
p14
|
||||
NsS'location'
|
||||
p15
|
||||
S'.tox/cyclic_deps/lib/python2.7/site-packages'
|
||||
p16
|
||||
sS'py_version'
|
||||
p17
|
||||
S'2.7'
|
||||
p18
|
||||
sS'_provider'
|
||||
p19
|
||||
(ipip._vendor.pkg_resources
|
||||
PathMetadata
|
||||
p20
|
||||
(dp21
|
||||
S'module_path'
|
||||
p22
|
||||
g16
|
||||
sS'egg_info'
|
||||
p23
|
||||
S'.tox/cyclic_deps/lib/python2.7/site-packages/CircularDependencyA-0.0.0-py2.7.egg-info'
|
||||
p24
|
||||
sbsbag1
|
||||
(g2
|
||||
g3
|
||||
Ntp25
|
||||
Rp26
|
||||
(dp27
|
||||
g7
|
||||
S'CircularDependencyB'
|
||||
p28
|
||||
sg9
|
||||
I-1
|
||||
sg10
|
||||
S'circulardependencyb'
|
||||
p29
|
||||
sg12
|
||||
S'0.0.0'
|
||||
p30
|
||||
sg14
|
||||
Nsg15
|
||||
g16
|
||||
sg17
|
||||
S'2.7'
|
||||
p31
|
||||
sg19
|
||||
(ipip._vendor.pkg_resources
|
||||
PathMetadata
|
||||
p32
|
||||
(dp33
|
||||
g22
|
||||
g16
|
||||
sg23
|
||||
S'.tox/cyclic_deps/lib/python2.7/site-packages/CircularDependencyB-0.0.0-py2.7.egg-info'
|
||||
p34
|
||||
sbsba.
|
|
@ -79,3 +79,33 @@ def test_render_tree_freeze():
|
|||
assert ' - SQLAlchemy==0.9.1' in lines
|
||||
assert '-e git+https://github.com/naiquevin/lookupy.git@cdbe30c160e1c29802df75e145ea4ad903c05386#egg=Lookupy-master' in lines
|
||||
assert 'itsdangerous==0.23' not in lines
|
||||
|
||||
|
||||
def test_render_tree_cyclic_dependency():
|
||||
with open('tests/cyclic_deps.pickle', 'rb') as f:
|
||||
cyclic_pkgs = pickle.load(f)
|
||||
|
||||
list_all = True
|
||||
|
||||
tree_str = render_tree(cyclic_pkgs, pkg_index, req_map, list_all,
|
||||
top_pkg_name, non_top_pkg_name)
|
||||
lines = set(tree_str.split('\n'))
|
||||
assert 'CircularDependencyA==0.0.0' in lines
|
||||
assert ' - CircularDependencyB [installed: 0.0.0]' in lines
|
||||
assert 'CircularDependencyB==0.0.0' in lines
|
||||
assert ' - CircularDependencyA [installed: 0.0.0]' in lines
|
||||
|
||||
|
||||
def test_render_tree_freeze_cyclic_dependency():
|
||||
with open('tests/cyclic_deps.pickle', 'rb') as f:
|
||||
cyclic_pkgs = pickle.load(f)
|
||||
|
||||
list_all = True
|
||||
|
||||
tree_str = render_tree(cyclic_pkgs, pkg_index, req_map, list_all,
|
||||
top_pkg_src, non_top_pkg_src)
|
||||
lines = set(tree_str.split('\n'))
|
||||
assert 'CircularDependencyA==0.0.0' in lines
|
||||
assert ' - CircularDependencyB==0.0.0' in lines
|
||||
assert 'CircularDependencyB==0.0.0' in lines
|
||||
assert ' - CircularDependencyA==0.0.0' in lines
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
CircularDependencyA
|
||||
CircularDependencyB
|
6
tox.ini
6
tox.ini
|
@ -8,7 +8,7 @@ envlist = py26, py27, py32, py33, py34
|
|||
|
||||
[testenv]
|
||||
commands =
|
||||
tox -e dummy
|
||||
tox -e dummy,cyclic_deps
|
||||
py.test {posargs:--cov pipdeptree --cov-report xml --cov-report html --cov-report term-missing tests/}
|
||||
deps =
|
||||
pytest
|
||||
|
@ -24,3 +24,7 @@ whitelist_externals = tox
|
|||
[testenv:dummy]
|
||||
deps = -r{toxinidir}/tests/virtualenvs/dummy_requirements.txt
|
||||
commands =
|
||||
|
||||
[testenv:cyclic_deps]
|
||||
deps = -r{toxinidir}/tests/virtualenvs/cyclic_deps_requirements.txt
|
||||
commands =
|
||||
|
|
Loading…
Reference in New Issue