Repository: spyder-ide/spyder

Issue:
Ghost completions
## Description of your problem

**What steps will reproduce the problem?**
1. Create a conda environment with no numpy
2. Run from boostrap
3. In editor: `import numpy; np.<TAB>`

**What is the expected output? What do you see instead?**
There should be no completions, but there are completions.

**Please provide any additional information below**
## Versions and main components
- Spyder Version: Master
- Python Version: 3.4
- Operating system: OSX 10.11
## Dependencies

Please go to the menu entry `Help > Optional Dependencies` (or
`Help > Dependencies`), press the button `Copy to clipboard`
and paste the contents below:
jedi >=0.8.1    :  0.9.0 (OK)
matplotlib >=1.0:  None (NOK)
nbconvert >=4.0 :  4.1.0 (OK)
numpy >=1.7     :  None (NOK)
pandas >=0.13.1 :  None (NOK)
pep8 >=0.6      :  1.7.0 (OK)
psutil >=0.3    :  3.4.2 (OK)
pyflakes >=0.5.0:  1.0.0 (OK)
pygments >=1.6  :  2.1 (OK)
pylint >=0.25   :  1.5.4 (OK)
qtconsole >=4.0 :  4.1.1 (OK)
rope >=0.9.4    :  0.9.4 (OK)
sphinx >=0.6.6  :  1.3.5 (OK)
sympy >=0.7.3   :  None (NOK)



Discussion:

Resolving patch:
diff --git a/spyderlib/utils/introspection/fallback_plugin.py b/spyderlib/utils/introspection/fallback_plugin.py
--- a/spyderlib/utils/introspection/fallback_plugin.py
+++ b/spyderlib/utils/introspection/fallback_plugin.py
@@ -17,7 +17,6 @@
 
 from spyderlib.utils.debug import log_dt
 from spyderlib.utils import sourcecode, encoding
-from spyderlib.utils.introspection.module_completion import module_completion
 from spyderlib.utils.introspection.manager import (
     DEBUG_EDITOR, LOG_FILENAME, IntrospectionPlugin)
 from spyderlib.utils.introspection.utils import (
@@ -35,34 +34,26 @@ def get_completions(self, info):
 
         Simple completion based on python-like identifiers and whitespace
         """
+        if not info['obj']:
+            return
         items = []
-        line = info['line'].strip()
-        is_from = line.startswith('from')
-        if ((line.startswith('import') or is_from and ' import' not in line)
-                and info['is_python_like']):
-            items += module_completion(info['line'], [info['filename']])
-            return [(i, 'module') for i in sorted(items)]
-        elif is_from and info['is_python_like']:
-            items += module_completion(info['line'], [info['filename']])
-            return [(i, '') for i in sorted(items)]
-        elif info['obj']:
-            base = info['obj']
-            tokens = set(re.findall(info['id_regex'], info['source_code']))
-            items = [item for item in tokens if
-                     item.startswith(base) and len(item) > len(base)]
-            if '.' in base:
-                start = base.rfind('.') + 1
-            else:
-                start = 0
-
-            items = [i[start:len(base)] + i[len(base):].split('.')[0]
-                     for i in items]
-            # get path completions
-            # get last word back to a space or a quote character
-            match = re.search('''[ "\']([\w\.\\\\/]+)\Z''', info['line'])
-            if match:
-                items += _complete_path(match.groups()[0])
-            return [(i, '') for i in sorted(items)]
+        base = info['obj']
+        tokens = set(re.findall(info['id_regex'], info['source_code']))
+        items = [item for item in tokens if
+                 item.startswith(base) and len(item) > len(base)]
+        if '.' in base:
+            start = base.rfind('.') + 1
+        else:
+            start = 0
+
+        items = [i[start:len(base)] + i[len(base):].split('.')[0]
+                 for i in items]
+        # get path completions
+        # get last word back to a space or a quote character
+        match = re.search('''[ "\']([\w\.\\\\/]+)\Z''', info['line'])
+        if match:
+            items += _complete_path(match.groups()[0])
+        return [(i, '') for i in sorted(items)]
 
     def get_definition(self, info):
         """
@@ -374,18 +365,6 @@ def __init__(self):
     comp = p.get_completions(CodeInfo('completions', code, len(code)))
     assert comp == [(encoding.to_unicode('álfa'), '')]
 
-    code = 'from numpy import one'
-    comp = p.get_completions(CodeInfo('completions', code, len(code)))
-    assert ('ones', '') in comp
-
-    comp = p.get_completions(CodeInfo('completions', code, len(code),
-        is_python_like=False))
-    assert not comp
-
-    code = 'from numpy.testing import (asse'
-    comp = p.get_completions(CodeInfo('completions', code, len(code)))
-    assert ('assert_equal', '') in comp
-
     code = '''
 def test(a, b):
     pass
diff --git a/spyderlib/utils/introspection/module_completion.py b/spyderlib/utils/introspection/module_completion.py
--- a/spyderlib/utils/introspection/module_completion.py
+++ b/spyderlib/utils/introspection/module_completion.py
@@ -286,6 +286,7 @@ def get_preferred_submodules():
             'PyQt4', 'PySide', 'os.path']
 
     submodules = []
+
     for m in mods:
         submods = get_submodules(m)
         submodules += submods
@@ -329,3 +330,5 @@ def get_preferred_submodules():
     assert module_completion(s + '(dum') == ['dump']
 
     assert module_completion(s + '(dump, Su') == ['SubElement']
+
+    assert 'os.path' in get_preferred_submodules()
diff --git a/spyderlib/utils/introspection/rope_plugin.py b/spyderlib/utils/introspection/rope_plugin.py
--- a/spyderlib/utils/introspection/rope_plugin.py
+++ b/spyderlib/utils/introspection/rope_plugin.py
@@ -9,6 +9,7 @@
 """
 
 import time
+import imp
 
 from spyderlib.config.base import get_conf_path, STDERR
 from spyderlib.utils import encoding, programs
@@ -62,8 +63,15 @@ def load_plugin(self):
         self.project = None
         self.create_rope_project(root_path=get_conf_path())
         submods = get_preferred_submodules()
+        actual = []
+        for submod in submods:
+            try:
+                imp.find_module(submod)
+                actual.append(submod)
+            except ImportError:
+                pass
         if self.project is not None:
-            self.project.prefs.set('extension_modules', submods)
+            self.project.prefs.set('extension_modules', actual)
 
     def get_completions(self, info):
         """Get a list of (completion, type) tuples using Rope"""


Test patch: