Repository: spyder-ide/spyder

Issue:
Spyder fails to import numpy on first line of a file
## Description of your problem



**What steps will reproduce the problem?**

1. Install spyder, numpy, and other packages in a virtualenv
2. start spyder
3. create a python script that just imports numpy
4. execute the first line of the script (run -> run cell)

**What is the expected output? What do you see instead?**

expected: success loading the module

actual:
Spyder Internal Console

This console is used to report application
internal errors and to inspect Spyder
internals with the following commands:
  spy.app, spy.window, dir(spy)

Please don't use it to run your code

>>> Traceback (most recent call last):
  File "/Users/seawolf/dev/py_virtualenv/machinelearning-udemy/lib/python3.6/site-packages/spyder/widgets/sourcecode/codeeditor.py", line 2698, in keyPressEvent
    self.fix_indent(comment_or_string=cmt_or_str)
  File "/Users/seawolf/dev/py_virtualenv/machinelearning-udemy/lib/python3.6/site-packages/spyder/widgets/sourcecode/codeeditor.py", line 1968, in fix_indent
    if prevtext.endswith(':') and self.is_python_like():
UnboundLocalError: local variable 'prevtext' referenced before assignment


**Please provide any additional information below**

all packages in the virtualenv:
alabaster==0.7.9
appnope==0.1.0
astroid==1.4.9
Babel==2.3.4
bleach==1.5.0
chardet==2.3.0
cycler==0.10.0
decorator==4.0.11
docutils==0.13.1
entrypoints==0.2.2
html5lib==0.9999999
imagesize==0.7.1
ipykernel==4.5.2
ipython==5.1.0
ipython-genutils==0.1.0
ipywidgets==5.2.2
isort==4.2.5
jedi==0.9.0
Jinja2==2.9.4
jsonschema==2.5.1
jupyter==1.0.0
jupyter-client==4.4.0
jupyter-console==5.0.0
jupyter-core==4.2.1
lazy-object-proxy==1.2.2
MarkupSafe==0.23
matplotlib==1.5.3
mccabe==0.5.3
mistune==0.7.3
nbconvert==5.1.1
nbformat==4.2.0
notebook==4.3.1
numpy==1.11.3
numpydoc==0.6.0
pandas==0.19.2
pandocfilters==1.4.1
pep8==1.7.0
pexpect==4.2.1
pickleshare==0.7.4
prompt-toolkit==1.0.9
psutil==5.0.1
ptyprocess==0.5.1
pyflakes==1.5.0
Pygments==2.1.3
pylint==1.6.4
pyparsing==2.1.10
PyQt5==5.7.1
python-dateutil==2.6.0
pytz==2016.10
pyzmq==16.0.2
QtAwesome==0.4.1
qtconsole==4.2.1
QtPy==1.2.0
requests==2.12.5
rope-py3k==0.9.4.post1
scipy==0.18.1
simplegeneric==0.8.1
sip==4.19
six==1.10.0
snowballstemmer==1.2.1
Sphinx==1.5.1
spyder==3.1.0
terminado==0.6
testpath==0.3
tornado==4.4.2
traitlets==4.3.1
wcwidth==0.1.7
widgetsnbextension==1.2.6
wrapt==1.10.8


## Versions and main components

* Spyder Version: 3.1.0
* Python Version: 3.6.0
* Operating system: OSX 10.12.2


## 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 :  1.5.3 (OK)
nbconvert >=4.0  :  5.1.1 (OK)
numpy >=1.7      :  1.11.3 (OK)
pandas >=0.13.1  :  0.19.2 (OK)
pep8 >=0.6       :  1.7.0 (OK)
psutil >=0.3     :  5.0.1 (OK)
pyflakes >=0.6.0 :  1.5.0 (OK)
pygments >=2.0   :  2.1.3 (OK)
pylint >=0.25    :  1.6.4 (OK)
qtconsole >=4.2.0:  4.2.1 (OK)
rope >=0.9.4     :  0.9.4-1 (OK)
sphinx >=0.6.6   :  1.5.1 (OK)
sympy >=0.7.3    :  None (NOK)



Discussion:
@andfoy, please take a look at this one.
@ccordoba12 I couldn't reproduce the error reported by the user.

## Version and main components

* Spyder Version: 3.1.1.dev0 c56ddb9
* Python Version: 3.5.2
* Qt Versions: 5.6.2, PyQt5 5.6 on Linux

## Dependencies
```
pyflakes >=0.6.0 :  1.5.0 (OK)
pep8 >=0.6       :  1.7.0 (OK)
pygments >=2.0   :  2.1.3 (OK)
qtconsole >=4.2.0:  4.2.1 (OK)
nbconvert >=4.0  :  5.1.1 (OK)
pandas >=0.13.1  :  None (NOK)
numpy >=1.7      :  1.12.0 (OK)
sphinx >=0.6.6   :  1.5.2 (OK)
rope >=0.9.4     :  0.10.3 (OK)
jedi >=0.8.1     :  0.9.0 (OK)
psutil >=0.3     :  5.0.1 (OK)
matplotlib >=1.0 :  2.0.0 (OK)
sympy >=0.7.3    :  None (NOK)
pylint >=0.25    :  1.6.5 (OK)

```

@seawolf42, please post the exact script that you're trying to run. I'm also unable to reproduce your error.
Here is some code explaining what I believe the problem is:

```python
block_nb = 0  # this value is given by the block number of the cursor's current position.
for prevline in range(block_nb - 1, -1, -1): 
    # range(-1, -1, -1) is empty, so the for loop will not execute
    # and prevtext will never initialize
    prevtext = text(prevline)

if prevtext:  # error occurs here because prevtext variable was never declared
    foo()
```

In `spyder/widgets/sourcecode/codeeditor.py`, this for loop is at line 1921 in Spyder version 3.1.0

Resolving patch:
diff --git a/spyder/widgets/sourcecode/codeeditor.py b/spyder/widgets/sourcecode/codeeditor.py
--- a/spyder/widgets/sourcecode/codeeditor.py
+++ b/spyder/widgets/sourcecode/codeeditor.py
@@ -1918,6 +1918,7 @@ def fix_indent(self, forward=True, comment_or_string=False):
         diff_curly = 0
         add_indent = False
         prevline = None
+        prevtext = ""
         for prevline in range(block_nb-1, -1, -1):
             cursor.movePosition(QTextCursor.PreviousBlock)
             prevtext = to_text_string(cursor.block().text()).rstrip()
@@ -2013,7 +2014,7 @@ def fix_indent(self, forward=True, comment_or_string=False):
                                 correct_indent = len(prevtext)
 
         if not (diff_paren or diff_brack or diff_curly) and \
-           not prevtext.endswith(':'):
+           not prevtext.endswith(':') and prevline:
             cur_indent = self.get_block_indentation(block_nb - 1)
             is_blank = not self.get_text_line(block_nb - 1).strip()
             prevline_indent = self.get_block_indentation(prevline)


Test patch:
diff --git a/spyder/widgets/sourcecode/tests/test_autoindent.py b/spyder/widgets/sourcecode/tests/test_autoindent.py
--- a/spyder/widgets/sourcecode/tests/test_autoindent.py
+++ b/spyder/widgets/sourcecode/tests/test_autoindent.py
@@ -139,6 +139,13 @@ def test_keep_unindent_if_blank():
     text = get_indent_fix(text)
     assert text == "    def f(x):\n        return x\n\n", repr(text)
 
+
+def test_first_line():
+    # Test fix_indent() when the cursor is on the first line.
+    text = get_indent_fix("import numpy")
+    assert text == "import numpy", repr(text)
+
+
 @pytest.mark.parametrize(
     "text_input, expected, test_text",
     [