davidhalter/jedi — pull request #483 by ColinDuquesnoy (2014-09-13 10:31:16+00:00)
Title: Fix RuntimeError: the PyQt5.QtCore and PyQt4.QtCore modules both wrap the QObject class

This issue happen when completing libraries that supports both PyQt4 and PyQt5 (if both frameworks has been installed on your system).

The problem is that jedi import both API resulting in a runtime error: ``RuntimeError: the PyQt5.QtCore and PyQt4.QtCore modules both wrap the QObject class``

To reproduce this error, just run the following script:
```python
import jedi
# Qt5 First
code = """
try:
from PyQt5 import QtWidgets as QtGui
except ImportError:
from PyQt4 import QtGui
QtGui.QIcon."""
print('QtGui.QIcon:', jedi.Script(code).completions())
code = """
try:
from PyQt5 import QtWidgets as QtGui
except ImportError:
from PyQt4 import QtGui
QtGui.QPushButton."""
print('QtGui.QPushButton:', jedi.Script(code).completions())
# Qt4 first
code = """
try:
from PyQt4 import QtGui
except ImportError:
from PyQt5 import QtWidgets as QtGui
QtGui.QIcon."""
print('QtGui.Icon:', jedi.Script(code).completions())
code = """
try:
from PyQt4 import QtGui
except ImportError:
from PyQt5 import QtWidgets as QtGui
QtGui.QPushButton."""
print('QtGui.QPushButton:', jedi.Script(code).completions())
```

Traceback:
```
Traceback (most recent call last):
File "/home/colin/jedi/runtime_error.py", line 9, in
print('QtGui.QIcon:', jedi.Script(code).completions())
File "/home/colin/jedi/jedi/api/__init__.py", line 157, in completions
completions = get_completions(user_stmt, b)
File "/home/colin/jedi/jedi/api/__init__.py", line 136, in get_completions
return self._simple_complete(path, like)
File "/home/colin/jedi/jedi/api/__init__.py", line 209, in _simple_complete
scopes = list(self._prepare_goto(path, True))
File "/home/colin/jedi/jedi/api/__init__.py", line 271, in _prepare_goto
scopes = self._evaluator.eval_statement(eval_stmt)
File "/home/colin/jedi/jedi/evaluate/cache.py", line 39, in wrapper
rv = function(obj, *args, **kwargs)
File "/home/colin/jedi/jedi/evaluate/recursion.py", line 24, in run
result = func(evaluator, stmt, *args, **kwargs)
File "/home/colin/jedi/jedi/debug.py", line 52, in wrapper
result = func(*args, **kwargs)
File "/home/colin/jedi/jedi/evaluate/__init__.py", line 133, in eval_statement
result = self.eval_expression_list(expression_list)
File "/home/colin/jedi/jedi/evaluate/__init__.py", line 172, in eval_expression_list
return precedence.process_precedence_element(self, p) or []
File "/home/colin/jedi/jedi/evaluate/precedence.py", line 247, in process_precedence_element
return evaluator.eval_statement_element(precedence)
File "/home/colin/jedi/jedi/evaluate/__init__.py", line 202, in eval_statement_element
return self.eval_call(element)
File "/home/colin/jedi/jedi/evaluate/__init__.py", line 213, in eval_call
return self.eval_call_path(path, scope, s.start_pos)
File "/home/colin/jedi/jedi/evaluate/__init__.py", line 231, in eval_call_path
types = imports.follow_imports(self, types)
File "/home/colin/jedi/jedi/evaluate/imports.py", line 519, in follow_imports
for r in ImportWrapper(evaluator, s).follow():
File "/home/colin/jedi/jedi/evaluate/imports.py", line 184, in follow
module, rest = self._importer.follow_file_system()
File "/home/colin/jedi/jedi/evaluate/cache.py", line 39, in wrapper
rv = function(obj, *args, **kwargs)
File "/home/colin/jedi/jedi/evaluate/imports.py", line 380, in follow_file_system
return self._real_follow_file_system()
File "/home/colin/jedi/jedi/evaluate/imports.py", line 402, in _real_follow_file_system
module, rest = self._follow_sys_path(sys_path_mod)
File "/home/colin/jedi/jedi/evaluate/imports.py", line 506, in _follow_sys_path
return _load_module(path, source, sys_path=sys_path), rest
File "/home/colin/jedi/jedi/evaluate/imports.py", line 564, in _load_module
return load(source) if cached is None else cached.module
File "/home/colin/jedi/jedi/evaluate/imports.py", line 557, in load
return compiled.load_module(path, name)
File "/home/colin/jedi/jedi/evaluate/compiled/__init__.py", line 326, in load_module
__import__(dotted_path)
RuntimeError: the PyQt5.QtCore and PyQt4.QtCore modules both wrap the QObject class
```

The fix is to use the names defined in the first loaded API, e.g. populate PyQt4.QtCore with symbols defined in PyQt5.QtCore. This fix also take care of the special case where PyQt4.QtGui has been split into PyQt5.QtGui and PyQt5.QtWidgets.

Here is the output of the test script with this fix:

```
QtGui.QIcon: [, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ]
QtGui.QPushButton: [, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ]
QtGui.Icon: [, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ]
QtGui.QPushButton: [, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ]

```

I have yet to add proper tests for that but I first wanted to have your opinion on the fix.