Repository: spyder-ide/spyder

Issue:
Can't use pythonw as interpreter when needed on Mac 
<!--- **PLEASE READ:** When submitting here, please ensure you've completed the following checklist and checked the boxes to confirm. Issue reports without it may be closed. Thanks! --->

### Issue Report Checklist

* [x] Searched the [issues page](https://github.com/spyder-ide/spyder/issues?q=is%3Aissue) for similar reports
* [ ] Read the relevant sections of the [Spyder Troubleshooting Guide](https://github.com/spyder-ide/spyder/wiki/Troubleshooting-Guide-and-FAQ) and followed its advice
* [ ] Reproduced the issue after updating with ``conda update spyder`` (or ``pip``, if not using Anaconda)
* [ ] Could not reproduce inside ``jupyter qtconsole`` (if console-related)
* [ ] Tried basic troubleshooting (if a bug/error)
    * [ x] Restarted Spyder
    * [ ] Reset preferences with ``spyder --reset``
    * [ ] Reinstalled the latest version of [Anaconda](https://www.anaconda.com/download/)
    * [ ] Tried the other applicable steps from the Troubleshooting Guide
* [x ] Completed the **Problem Description**, **Steps to Reproduce** and **Version** sections below


## Problem Description
Same problem as in #7059 (Can't use pythonw as interpreter when needed on Mac). Sometimes one needs to use pythonw as the interpreter for debugging. It would be nice to see this fixed in 4.2.2. FWIW this has been addressed in 5.0.0dev. 


### What steps reproduce the problem?

1. Select the preferences menu item
2. Select the Python interpreter
3. Select pythonw; press OK
4. note error: "Invalid file path:..."

### What is the expected output? What do you see instead?
Expected: pythonw is used (which allows work with wxpython and probably other stuff).

Instead: above error message


## Versions
Installed from Spyder standalone installer; attempting to use external conda-installed python interpreter

* Spyder version: 4.2.1
* Python version: 3.9.1 64-bit 
* Qt version: 5.12.10
* PyQt version: 5.12.3
* Operating System name/version: 19.6.0

### Dependencies
<!--- Please go to the menu entry Help > Dependencies,
press the Copy to clipboard button and paste below --->

```

# Mandatory:
applaunchservices >=0.1.7       :  0.2.1 (OK)
atomicwrites >=1.2.0            :  1.4.0 (OK)
chardet >=2.0.0                 :  4.0.0 (OK)
cloudpickle >=0.5.0             :  1.6.0 (OK)
diff_match_patch >=20181111     :  20200713 (OK)
intervaltree >=3.0.2            :  3.1.0 (OK)
IPython >=7.6.0                 :  7.19.0 (OK)
jedi =0.17.2                    :  0.17.2 (OK)
jsonschema >=3.2.0              :  3.2.0 (OK)
keyring >=17.0.0                :  21.5.0 (OK)
nbconvert >=4.0                 :  6.0.7 (OK)
numpydoc >=0.6.0                :  1.1.0 (OK)
parso =0.7.0                    :  0.7.0 (OK)
pexpect >=4.4.0                 :  4.8.0 (OK)
pickleshare >=0.4               :  0.7.5 (OK)
psutil >=5.3                    :  5.7.3 (OK)
pygments >=2.0                  :  2.7.3 (OK)
pylint >=1.0                    :  2.6.0 (OK)
pyls >=0.36.2;<1.0.0            :  0.36.2 (OK)
pyls_black >=0.4.6              :  0.4.6 (OK)
pyls_spyder >=0.3.0             :  0.3.0 (OK)
qdarkstyle >=2.8                :  2.8.1 (OK)
qtawesome >=0.5.7               :  1.0.2 (OK)
qtconsole >=5.0.1               :  5.0.1 (OK)
qtpy >=1.5.0                    :  1.9.0 (OK)
setuptools >=39.0.0             :  51.0.0 (OK)
sphinx >=0.6.6                  :  3.3.1 (OK)
spyder_kernels >=1.10.1;<1.11.0 :  1.10.1 (OK)
textdistance >=4.2.0            :  4.2.0 (OK)
three_merge >=0.1.1             :  0.1.1 (OK)
watchdog >=0.10.3               :  1.0.2 (OK)
zmq >=17                        :  20.0.0 (OK)

# Optional:
cython >=0.21                   :  0.29.21 (OK)
matplotlib >=2.0.0              :  3.3.3 (OK)
numpy >=1.7                     :  1.19.4 (OK)
pandas >=1.1.1                  :  None (NOK)
scipy >=0.17.0                  :  1.5.4 (OK)
sympy >=0.7.3                   :  1.7.1 (OK)
```



Discussion:
Unfortunately, we don't have time to address this right now. So, you're welcome to submit a pull request to implement this. Otherwise, you'll have to wait until Spyder 5 is released.
Same problem in spyder 5.2.2 (downloaded yesterday.) Was working for me at some point.
Yeah, I think we added more strict validations for the executable users want to use as Python interpreter, and that ruled out this case. But that shouldn't be the case.

@mrclary, could you give us a hand with this one?

Resolving patch:
diff --git a/spyder/utils/conda.py b/spyder/utils/conda.py
--- a/spyder/utils/conda.py
+++ b/spyder/utils/conda.py
@@ -10,13 +10,9 @@
 import json
 import os
 import os.path as osp
-import subprocess
 import sys
 
-from spyder.config.base import running_in_mac_app, get_home_dir
-from spyder.utils.programs import (find_program, run_program,
-                                   run_shell_command)
-
+from spyder.utils.programs import find_program, run_program, run_shell_command
 
 WINDOWS = os.name == 'nt'
 CONDA_ENV_LIST_CACHE = {}
diff --git a/spyder/utils/programs.py b/spyder/utils/programs.py
--- a/spyder/utils/programs.py
+++ b/spyder/utils/programs.py
@@ -30,9 +30,8 @@
 import psutil
 
 # Local imports
-from spyder.config.base import (is_stable_version, running_under_pytest,
-                                get_home_dir, running_in_mac_app)
-from spyder.config.utils import is_anaconda
+from spyder.config.base import (running_under_pytest, get_home_dir,
+                                running_in_mac_app)
 from spyder.py3compat import PY2, is_text_string, to_text_string
 from spyder.utils import encoding
 from spyder.utils.misc import get_python_executable
@@ -978,34 +977,42 @@ def is_python_interpreter_valid_name(filename):
 
 def is_python_interpreter(filename):
     """Evaluate whether a file is a python interpreter or not."""
+    # Must be imported here to avoid circular import
+    from spyder.utils.conda import is_conda_env
+
     real_filename = os.path.realpath(filename)  # To follow symlink if existent
+
     if (not osp.isfile(real_filename) or
-        not is_python_interpreter_valid_name(filename)):
+        not is_python_interpreter_valid_name(real_filename)):
         return False
-    elif is_pythonw(filename):
+
+    # File exists and has valid name
+    is_text_file = encoding.is_text_file(real_filename)
+
+    if is_pythonw(real_filename):
         if os.name == 'nt':
             # pythonw is a binary on Windows
-            if not encoding.is_text_file(real_filename):
+            if not is_text_file:
                 return True
             else:
                 return False
         elif sys.platform == 'darwin':
             # pythonw is a text file in Anaconda but a binary in
             # the system
-            if is_anaconda() and encoding.is_text_file(real_filename):
+            if is_conda_env(pyexec=real_filename) and is_text_file:
                 return True
-            elif not encoding.is_text_file(real_filename):
+            elif not is_text_file:
                 return True
             else:
                 return False
         else:
             # There's no pythonw in other systems
             return False
-    elif encoding.is_text_file(real_filename):
+    elif is_text_file:
         # At this point we can't have a text file
         return False
     else:
-        return check_python_help(filename)
+        return check_python_help(real_filename)
 
 
 def is_pythonw(filename):


Test patch: