Repository: ansible/ansible

Issue:
"pause" module fails with NameError when "curses" is not installed
<!---
Verify first that your issue/request is not already reported on GitHub.
THIS FORM WILL BE READ BY A MACHINE, COMPLETE ALL SECTIONS AS DESCRIBED.
Also test if the latest release, and devel branch are affected too.
ALWAYS add information AFTER (OUTSIDE) these html comments.
Otherwise it may end up being automatically closed by our bot. -->

##### SUMMARY
The "pause" module fails with a NameError when the curses Python module is not available.

```
Traceback (most recent call last):
  File "/usr/local/python/bin/ansible-playbook", line 118, in <module>
    exit_code = cli.run()
  File "/usr/local/python/lib/python2.7/site-packages/ansible/cli/playbook.py", line 122, in run
    results = pbex.run()
  File "/usr/local/python/lib/python2.7/site-packages/ansible/executor/playbook_executor.py", line 159, in run
    result = self._tqm.run(play=play)
  File "/usr/local/python/lib/python2.7/site-packages/ansible/executor/task_queue_manager.py", line 289, in run
    play_return = strategy.run(iterator, play_context)
  File "/usr/local/python/lib/python2.7/site-packages/ansible/plugins/strategy/linear.py", line 247, in run
    action = action_loader.get(task.action, class_only=True)
  File "/usr/local/python/lib/python2.7/site-packages/ansible/plugins/loader.py", line 366, in get
    self._module_cache[path] = self._load_module_source(name, path)
  File "/usr/local/python/lib/python2.7/site-packages/ansible/plugins/loader.py", line 345, in _load_module_source
    module = imp.load_source(full_name, path, module_file)
  File "/usr/local/python/lib/python2.7/site-packages/ansible/plugins/action/pause.py", line 44, in <module>
    except (ImportError, curses.error):
NameError: name 'curses' is not defined
```

Caused by this code block introduced by https://github.com/ansible/ansible/pull/40134 to fix #35372:

```python
try:
    import curses
    curses.setupterm()
    HAS_CURSES = True
except (ImportError, curses.error):
    HAS_CURSES = False
```

A better fix would be to nest the curses.error try-catch within the block.

##### ISSUE TYPE
 - Bug Report

##### COMPONENT NAME
plugins/action/pause.py

##### ANSIBLE VERSION
ansible 2.5.4
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/etc/ansible/modules']
  ansible python module location = /usr/local/python/lib/python2.7/site-packages/ansible
  executable location = /usr/local/python/bin/ansible
  python version = 2.7.10 (default, Oct 11 2015, 23:13:31) [GCC 4.8.3 20140911 (Red Hat 4.8.3-9)]

##### CONFIGURATION
N/A

##### OS / ENVIRONMENT
N/A

##### STEPS TO REPRODUCE
On a machine without "curses", run:

> $ ansible localhost -m pause -a 'seconds=1'
> ERROR! Unexpected Exception, this is probably a bug: name 'curses' is not defined
> to see the full traceback, use -vvv

##### EXPECTED RESULTS
N/A

##### ACTUAL RESULTS
See above.


Discussion:
Files identified in the description:
* [lib/ansible/modules/utilities/logic/pause.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/utilities/logic/pause.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @tbielawa
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
We could also note the dependency in the docs for the pause module.

Resolving patch:
diff --git a/lib/ansible/plugins/action/pause.py b/lib/ansible/plugins/action/pause.py
--- a/lib/ansible/plugins/action/pause.py
+++ b/lib/ansible/plugins/action/pause.py
@@ -39,9 +39,14 @@
 
 try:
     import curses
-    curses.setupterm()
-    HAS_CURSES = True
-except (ImportError, curses.error):
+
+    # Nest the try except since curses.error is not available if curses did not import
+    try:
+        curses.setupterm()
+        HAS_CURSES = True
+    except curses.error:
+        HAS_CURSES = False
+except ImportError:
     HAS_CURSES = False
 
 if HAS_CURSES:


Test patch: