Pyreverse: ValueError: need more than 1 value to unpack
Originally reported by: Jorge Araya Navarro (BitBucket: shackra, GitHub: @shackra?)
I'm not sure what's happening...
#!bash
jorge [~/coders/desarrollo/thomas-aquinas] ~> pyreverse -c cocos2d -a 1 -s 1 -f ALL -o png summa/
parsing summa/__init__.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/utils.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/__init__.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/framegrabber.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/summanode.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/collision_model.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/text.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/menu.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/particle.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/batch.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/director.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/shader.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/wired.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/rect.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/skeleton.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/gl_framebuffer_object.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/camera.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/draw.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/tiles.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/custom_clocks.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/path.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/sprite.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/grid.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/particle_systems.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/scene.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/euclid.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/scenes/__init__.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/scenes/transitions.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/scenes/pause.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/actions/__init__.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/actions/instant_actions.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/actions/base_actions.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/actions/grid3d_actions.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/actions/camera_actions.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/actions/tiledgrid_actions.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/actions/move_actions.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/actions/basegrid_actions.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/actions/interval_actions.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/actions/quadmoveby_actions.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/audio/__init__.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/audio/music.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/audio/vector.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/audio/system.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/audio/objectbase.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/audio/sftime.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/audio/libs.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/audio/soundstatus.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/audio/actions.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/audio/sfmusic.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/audio/effect.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/audio/listener.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/audio/exceptions.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/layer/__init__.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/layer/base_layers.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/layer/util_layers.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/layer/python_interpreter.py...
parsing /home/jorge/coders/desarrollo/thomas-aquinas/summa/layer/scrolling.py...
Traceback (most recent call last):
File "/usr/bin/pyreverse", line 9, in <module>
load_entry_point('pylint==0.28.0', 'console_scripts', 'pyreverse')()
File "/usr/lib/python2.7/site-packages/pylint-0.28.0-py2.7.egg/pylint/__init__.py", line 39, in run_pyreverse
Run(sys.argv[1:])
File "/usr/lib/python2.7/site-packages/pylint-0.28.0-py2.7.egg/pylint/pyreverse/main.py", line 98, in __init__
sys.exit(self.run(args))
File "/usr/lib/python2.7/site-packages/pylint-0.28.0-py2.7.egg/pylint/pyreverse/main.py", line 112, in run
diadefs = handler.get_diadefs(project, linker)
File "/usr/lib/python2.7/site-packages/pylint-0.28.0-py2.7.egg/pylint/pyreverse/diadefslib.py", line 226, in get_diadefs
diagrams.append(generator.class_diagram(project, klass))
File "/usr/lib/python2.7/site-packages/pylint-0.28.0-py2.7.egg/pylint/pyreverse/diadefslib.py", line 194, in class_diagram
module, klass = klass.rsplit('.', 1)
ValueError: need more than 1 value to unpack
jorge [~/coders/desarrollo/thomas-aquinas] ~>
Then I tried to parse that file directly to see what happen, and I got this:
#!bash
jorge [~/coders/desarrollo/thomas-aquinas] ~> pyreverse -c cocos2d -a 1 -s 1 -f ALL -o png summa/layer/scrolling.py
parsing summa/layer/scrolling.py...
Traceback (most recent call last):
File "/usr/bin/pyreverse", line 9, in <module>
load_entry_point('pylint==0.28.0', 'console_scripts', 'pyreverse')()
File "/usr/lib/python2.7/site-packages/pylint-0.28.0-py2.7.egg/pylint/__init__.py", line 39, in run_pyreverse
Run(sys.argv[1:])
File "/usr/lib/python2.7/site-packages/pylint-0.28.0-py2.7.egg/pylint/pyreverse/main.py", line 98, in __init__
sys.exit(self.run(args))
File "/usr/lib/python2.7/site-packages/pylint-0.28.0-py2.7.egg/pylint/pyreverse/main.py", line 112, in run
diadefs = handler.get_diadefs(project, linker)
File "/usr/lib/python2.7/site-packages/pylint-0.28.0-py2.7.egg/pylint/pyreverse/diadefslib.py", line 226, in get_diadefs
diagrams.append(generator.class_diagram(project, klass))
File "/usr/lib/python2.7/site-packages/pylint-0.28.0-py2.7.egg/pylint/pyreverse/diadefslib.py", line 199, in class_diagram
klass = module.ilookup(klass).next()
File "/usr/lib/python2.7/site-packages/logilab_astng-0.24.3-py2.7.egg/logilab/astng/bases.py", line 124, in _infer_stmts
raise InferenceError(str(stmt))
logilab.astng.exceptions.InferenceError: None
jorge [~/coders/desarrollo/thomas-aquinas] ~>
The file is right here shackra/thomas-aquinas/src/summa/layer/scrolling.py...
- Bitbucket: https://bitbucket.org/logilab/pylint/issue/22
Original comment by Emile Anclin (BitBucket: anclin, GitHub: @anclin?):
It seems, it is a command line parsing errror of the "-c" option and comes in many variations:
#!python
pyreverse dynamics/* -c -p stroumpf
Traceback (most recent call last):
File "/home/e1000/bin/pyreverse", line 3, in <module>
run_pyreverse()
...
File "/home/e1000/src/logilab/common/modutils.py", line 577, in _search_zip
raise ImportError('No module named %s' % '.'.join(modpath))
ImportError: No module named stroumpf
After the '-c', we can also use a non existing '-E' option, and I get:
#!python
pyreverse dynamics/controler.py -c -E
...
raise InferenceError(str(stmt))
astroid.exceptions.InferenceError: None
Parsing the whole directory with the non sens option '-E' yields yet another error:
#!python
pyreverse dynamics/* -o png -c -E
File "/home/e1000/src/pylint/pyreverse/diadefslib.py", line 196, in class_diagram
module, klass = klass.rsplit('.', 1)
ValueError: need more than 1 value to unpack
The problems with the '-E' are triggered the same way with the valid '-p' option...
Original comment by Emile Anclin (BitBucket: anclin, GitHub: @anclin?):
I tried to understand the problem: let's take the example
#!python
pyreverse dynamics/ -A 1 -c -p name
At logilab.common.configuration line 685, in the load_command_line_configuration of OptionsManagerMixIn we have:
#!python
(options, args) = self.cmdline_parser.parse_args(args=args)
before line 685 we have:
#!python
args = ['dynamics/', '-A', '1', '-c', '-p', 'name']
after line 685:
#!python
options = {'show_associated': None, 'module_names': None, 'output_format': None, 'only_classnames': None, 'project': None, 'show_ancestors': None, 'classes': ['-p'], 'mode': None, 'show_builtin': None, 'black_list': None}
args = ['dynamics/', '1', 'name']
Instead we should have a option error message. The called parse_args method is from optparse import OptionParser; Pyreverse depends on the OptionsManagerMixIn through the ConfigurationMixIn(OptionsManagerMixIn, OptionsProviderMixIn) and pylint.pyreverse.main.Run(ConfigurationMixIn) . However ihmo, this complicated inheritage does not seem to be needed; the other OptionsProviderMixIn used for Pyreverse is AstroidManager(OptionsProviderMixIn), providing only the --filter and --projects options, and they are only needed for Pyreverse.
So, I think, we can remove these dependencies and just rewrite the pyreverse options with a simple Optparse usage. Is this ok for you?
Original comment by Sylvain Thénault (BitBucket: sthenault, GitHub: @sthenault?):
Hi Emile,
I'm not sure your analysis is related to the original poster's problem. You're right there seem to have a problem with unknown option which are not reported as error though.
I don't think going back to optparse is the solution. Pylint use logilab.common.configuration and doesn't suffer from this problem. Also, we should benefit from it to rewrite the very dumb (broken?) pyreverse.rc support.
Original comment by Emile Anclin (BitBucket: anclin, GitHub: @anclin?):
Yes, I was wrong, the original problem does not has a malformed command line in the first place, except that there is no class "cocos2d" in the file proposed in the link of the original problem ... I'll open another ticket adressing the command line problem.
Original comment by Emile Anclin (BitBucket: anclin, GitHub: @anclin?):
Ok, I think the problem is the definition of the "-c" option: right now, it expects (de facto):
- to be used with only one module, not even a package (here is first crash of the original problem )
- after '-c', there should be the name of one class defined in the module (second crash of the original problem; it will also crash if the class is just imported in that module)
Bad enough, but the value of the '-c' option is put in a list ... (I know I coded that option, so I'm supposed know what it should do :-/ )... I suggest the following solution:
- An explaining message if the above conditions are not true and stop the program
- make '-c' accept a CSV list of classes to generate several diagrams
- Possibly add a '-C' option to generate class diagrams for all classes in the project
Original comment by Sylvain Thénault (BitBucket: sthenault, GitHub: @sthenault?):
I would go for 2.
- sounds like the default behaviour, eg without option
Original comment by Emile Anclin (BitBucket: anclin, GitHub: @anclin?):
Sorry, maybe I was not clear enough:
- the -c option will generate a diagram of one Class called 'Class.dot'
- whereas 'ASmy (without -c) will generate a diagram of all classes of the project's modules called 'classes<project_Name>.dot_' .
With -ASmy (without -c), the diagram might become too big, like :
#!python
pyreverse astroid.node_classes -ASmy
so my intention of the -c was having an option representing only one class..
The original post points out two bugs which are independent of his code:
A. pyreverse always crashes when used with -c option and more than one module, like :
#!python
pyreverse -c Instance astroid.builder astroid.bases # two modules
pyreverse -c Instance astroid # a package with several modules modules
B. pyreverse always crashes when used with -c option, one module which does not define the mentionned class, like :
#!python
pyreverse -c SomeClass astroid.builder
B1. pyreverse always crashes when used with -c and two comma separated classes, like:
#!python
pyreverse -c Instance,Statement astroid.bases
- was meant to fix those bugs A. and B.
- should fix B1. (it is more or less a bug and/or an obvious improvement)
- would just be a possible other improvement
Original comment by Sylvain Thénault (BitBucket: sthenault, GitHub: @sthenault?):
ok, then at least A and B should be fixed, probably by outputing proper error messages
I had exactly this same problem. It was because I was saying -c classname instead of -c top_level_module.module1.module2.module3.classname
yup, I reported this originally
I have the same issue. Has there been any progress on this ?
@lovasoa apparentely no one worked on it yet, I'd be glad to review a merge request that fix this.
Is anyone able to provide accessible code (link in original issue isn't) to reproduce this?
@clavedeluna theoretically this should work as a minimal example with our own codebase:
pyreverse -c FileItem pylint
As simsong rightly pointed out, the error here is that one needs to provide the fully qualified classname instead, so this should work:
pyreverse -c pylint.typing.FileItem pylint
However another bug is currently hiding it if you try to run this example on our current main branch:
parsing D:\Programming\git-forks\pylint\pylint\utils\utils.py...
sys.exit(load_entry_point('pylint', 'console_scripts', 'pyreverse')())
File "d:\programming\git-forks\pylint\pylint\__init__.py", line 74, in run_pyreverse
PyreverseRun(argv or sys.argv[1:])
File "d:\programming\git-forks\pylint\pylint\pyreverse\main.py", line 228, in __init__
sys.exit(self.run(args))
File "d:\programming\git-forks\pylint\pylint\pyreverse\main.py", line 243, in run
diadefs = handler.get_diadefs(project, linker)
File "d:\programming\git-forks\pylint\pylint\pyreverse\diadefslib.py", line 225, in get_diadefs
diagrams.append(generator.class_diagram(project, klass))
File "d:\programming\git-forks\pylint\pylint\pyreverse\diadefslib.py", line 196, in class_diagram
self.extract_classes(klass, anc_level, association_level)
File "d:\programming\git-forks\pylint\pylint\pyreverse\diadefslib.py", line 113, in extract_classes
self.add_class(klass_node)
File "d:\programming\git-forks\pylint\pylint\pyreverse\diadefslib.py", line 77, in add_class
self.linker.visit(node)
File "d:\programming\git-forks\pylint\pylint\pyreverse\utils.py", line 162, in visit
methods[0](node)
File "d:\programming\git-forks\pylint\pylint\pyreverse\inspector.py", line 195, in visit_classdef
self.associations_handler.handle(assignattr, node)
File "d:\programming\git-forks\pylint\pylint\pyreverse\inspector.py", line 371, in handle
if isinstance(node.parent.value, astroid.node_classes.Name):
AttributeError: 'ClassDef' object has no attribute 'value'. Did you mean: 'values'?
It still works on 2.15.9 however. I opened https://github.com/PyCQA/pylint/issues/8031 for the new bug.