Repository: spyder-ide/spyder
Pull request: PR: Add support to run files in external system terminal for macOS
<!--- Make sure to read the Contributing Guidelines:                   --->
<!--- https://github.com/spyder-ide/spyder/blob/master/CONTRIBUTING.md --->
<!--- and follow PEP 8, PEP 257 and Spyder's code style:               --->
<!--- https://github.com/spyder-ide/spyder/wiki/Dev:-Coding-Style      --->

## Description of Changes


* [ ] Wrote at least one-line docstrings (for any new functions)
* [ ] Added unit test(s) covering the changes (if testable)
<!--- Remember that an image/animation is worth a thousand words! --->
* [x] Included a screenshot or animation (if affecting the UI, see [Licecap](https://www.cockos.com/licecap/))



<!--- Explain what you've done and why --->
Add the option for running programs in an external system terminal in macOS

![image](https://user-images.githubusercontent.com/20992645/60073230-7c623980-96e5-11e9-8226-45cef6191dce.png)

### Issue(s) Resolved

<!--- List the issue(s) below, in the form "Fixes #1234"; one per line --->

Fixes #5062


### Affirmation

By submitting this Pull Request or typing my (user)name below,
I affirm the [Developer Certificate of Origin](https://developercertificate.org)
with respect to all commits and content included in this PR,
and understand I am releasing the same under Spyder's MIT (Expat) license.

<!--- TYPE YOUR USER/NAME AFTER THE FOLLOWING: --->
I certify the above statement is true and correct: Steff456

<!--- Thanks for your help making Spyder better for everyone! --->


Problem statement:
Run in external system terminal doesn't work in macOS
## Description

**What steps will reproduce the problem?**

1. open python file
2. "run"->"configuration per file.."
3. set "execute in an external system terminal"
4. "run"
5. nothing happens

**What is the expected output? What do you see instead?**

I expected Terminal app appearance, but terminal doesn't load


**Please provide any additional information below**



## Version and main components

* Spyder Version: 3.2.1 
* Python Version: 3.6.1 and 2.7
* Qt Versions: 5.6.2, PyQt5 5.6 on Darwin

## Dependencies
```
pyflakes >=0.6.0 :  1.5.0 (OK)
pycodestyle >=2.3:  2.3.1 (OK)
pygments >=2.0   :  2.2.0 (OK)
pandas >=0.13.1  :  0.20.1 (OK)
numpy >=1.7      :  1.12.1 (OK)
sphinx >=0.6.6   :  1.5.6 (OK)
rope >=0.9.4     :  0.9.4-1 (OK)
jedi >=0.9.0     :  0.10.2 (OK)
psutil >=0.3     :  5.2.2 (OK)
nbconvert >=4.0  :  5.1.1 (OK)
sympy >=0.7.3    :  1.0 (OK)
cython >=0.21    :  0.25.2 (OK)
qtconsole >=4.2.0:  4.3.0 (OK)
IPython >=4.0    :  5.3.0 (OK)
pylint >=0.25    :  1.6.4 (OK)

```

Best regards,
Andrew

Hints from issue discussion:
We don't have support for running files in system terminals in macOS, but we'll work to add it in a future release.
Thank you!
@juanis2112 I'm about to push a PR with some fixes and improvements to this feature and its tests on Windows and Linux. After that, might you perhaps be able to implement and test a code snippet (e.g. [something like this](https://stackoverflow.com/questions/4404242/programmatically-launch-terminal-app-with-a-specified-command-and-custom-colors) ) to add this functionality? We've had requests for it on our Gitter and it would help bring our macOS platform closer to parity with the others.

Commit message: add appscript to setup.py

Patch to review:
diff --git a/continuous_integration/azure/install.sh b/continuous_integration/azure/install.sh
index 23bb58e76ee..efbf1651dea 100755
--- a/continuous_integration/azure/install.sh
+++ b/continuous_integration/azure/install.sh
@@ -3,7 +3,7 @@
 # -- Installl dependencies
 if [ "$USE_CONDA" = "yes" ]; then
     # Install main dependencies
-    conda install -q -y -c spyder-ide --file requirements/conda.txt
+    conda install -q -y -c spyder-ide --file requirements/conda_macOS.txt
 
     # Install test ones
     conda install -q -y -c spyder-ide --file requirements/tests.txt
diff --git a/requirements/conda_macOS.txt b/requirements/conda_macOS.txt
new file mode 100644
index 00000000000..6cfb4b7238b
--- /dev/null
+++ b/requirements/conda_macOS.txt
@@ -0,0 +1,23 @@
+cloudpickle
+pygments >=2.0
+qtconsole >=4.5.0
+nbconvert
+sphinx
+pylint
+psutil
+qtawesome >=0.5.2
+qtpy >=1.5.0
+pickleshare
+pyzmq
+chardet >=2.0.0
+numpydoc
+pyqt <5.10
+keyring
+spyder-kernels >=1.2
+python-language-server >=0.19
+qdarkstyle >=2.6.4
+atomicwrites
+diff-match-patch
+pexpect
+watchdog
+appscript
diff --git a/setup.py b/setup.py
index ba2f9e2ffdc..e6870f84ba5 100644
--- a/setup.py
+++ b/setup.py
@@ -217,6 +217,8 @@ def run(self):
     'atomicwrites',
     'diff-match-patch',
     'watchdog',
+    # Only require appscript for macOS
+    'appscript;sys_platform=="darwin"',
     # Don't require keyring for Python 2 and Linux
     # because it depends on system packages
     'keyring;sys_platform!="linux2"',
diff --git a/spyder/utils/programs.py b/spyder/utils/programs.py
index 21908011f10..1fe72bc301d 100644
--- a/spyder/utils/programs.py
+++ b/spyder/utils/programs.py
@@ -315,7 +315,7 @@ def run_python_script_in_terminal(fname, wdir, args, interact,
                                  _("It was not possible to run this file in "
                                    "an external terminal"),
                                  QMessageBox.Ok)
-    elif os.name == 'posix':
+    elif sys.platform.startswith('linux'):
         programs = [{'cmd': 'gnome-terminal',
                      'wdir-option': '--working-directory',
                      'execute-option': '-x'},
@@ -340,7 +340,13 @@ def run_python_script_in_terminal(fname, wdir, args, interact,
                 else:
                     run_program(program['cmd'], arglist)
                 return
-        # TODO: Add a fallback to OSX
+    elif sys.platform == 'darwin':
+        import appscript
+        command = ""
+        if wdir:
+            command += "cd {0}\n".format(wdir)
+        command += "{0} {1}".format(p_args[0], p_args[1])
+        appscript.app('Terminal').do_script(command)
     else:
         raise NotImplementedError
 


Code review comments:
diff_hunk: @@ -340,7 +340,13 @@ def run_python_script_in_terminal(fname, wdir, args, interact,
                 else:
                     run_program(program['cmd'], arglist)
                 return
-        # TODO: Add a fallback to OSX
+    elif sys.platform == 'darwin':
+        import appscript
+        command = ""
+        if wdir:
+            command += "cd {0}\n".format(wdir)
+        command += "{0} {1}".format(p_args[0], p_args[1])
+        appscript.app('Terminal').do_script(command)
path: spyder/utils/programs.py
text: @user1:
As discussed in our call earlier @author 

```python
        fpath = os.path.join(TEMP_PATH, 'a.tool')
        with open(fpath, 'w') as f:
            f.write(command)
        os.chmod(path, 0o777)
        subprocess.call(['open ' + fpath], shell=True)
```