Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Windows: Can't execute new python file on network drive #20003

Closed
athompson673 opened this issue Nov 7, 2022 · 9 comments
Closed

Windows: Can't execute new python file on network drive #20003

athompson673 opened this issue Nov 7, 2022 · 9 comments

Comments

@athompson673
Copy link
Contributor

New file created by project pane: new: python file has UNC file path without drive letter. command line generates the following message when given a UNC path.

CMD.EXE was started with the above path as the current directory.
UNC paths are not supported. Defaulting to Windows directory.

With the run settings to "execute in an external terminal", running the file appears to do nothing at all. Opening the directory in an explorer window from spyder similarly puts the UNC path into explorer, so bat files from that window can't be executed (which is how I found the error text)

repro steps:

  • windows
  • on a mapped network share
  • create a new project
  • create a new python file
  • can't run file in external terminal with f5
  • close and re-open file
  • file now refers to drive letter
  • can run file with f5

spyder version info:

  • Spyder version: 5.4.0 (pip)
  • Python version: 3.11.0 64-bit
  • Qt version: 5.15.2
  • PyQt5 version: 5.15.7
  • Operating System: Windows 10
@ccordoba12
Copy link
Member

Hey @athompson673, thanks for reporting. This is interesting:

  • create a new python file
  • can't run file in external terminal with f5
  • close and re-open file
  • file now refers to drive letter

Are you saving your new Python file after creating it from the Projects pane?

@athompson673
Copy link
Contributor Author

athompson673 commented Nov 8, 2022

@ccordoba12 Afaik, the file is created then saved immediately (with the default coding line and docstring). If I type some code, then save it, the content is correctly saved (I went and found the file and opened it separately in notepad++). The filename at the top of the editor widget however remains as a UNC path "\\server\folder\folder\test.py" until I close and re-open the file in another way: "Y:\folder\test.py". When the file is a UNC path, it cannot be run with CMD.

create new file from project window:

image

Example of file after creation:

image

after closing and re-opening the file:

image

in theory this could be side-stepped by editing spyder/utils/programs.run_python_script_in_terminal to re-write the drive to the drive letter (though I can't immediately find a way to convert from a drive to a drive letter, only the reverse..)

@athompson673
Copy link
Contributor Author

athompson673 commented Nov 9, 2022

I came up with a dirty hack that does the above (re-write drive letter), and I don't like it, but it does allow the file to be run with a UNC path:

starting inside run_python_script_in_terminal:

    if os.name == 'nt':
        if wdir is not None:
            # wdir can come with / as os.sep, so we need to take care of it.
            wdir = wdir.replace('/', '\\')
            #!!! dirty hack (fix for UNC file path cwd not supported on cmd.exe)
            drives = { osp.splitdrive(osp.realpath(chr(x) + ":"))[0].lower(): chr(x) + ":" for x in range(65,91) if osp.exists(chr(x) + ":") } #reverse map available drives to realpath
            drive, tail = osp.splitdrive(wdir)
            if drive.lower() in drives:
                wdir = osp.join(drives[drive], tail) #apply letter drive instead of realpath to wdir

Even more testing unfortunately didn't answer any of my questions...

Writing my own Popen command in a naked python prompt with cwd=r"\\some\unc\path" at least calls the file, but with the error message, and naturally the wrong cwd (which then may cause errors with the script itself). I cannot understand why with sypder no command window appears at all (this should be mostly the same command), and I cannot seem to find the output of the UNC path warning from cmd.exe at all (doesn't show up in internal console):

image

@ccordoba12
Copy link
Member

The filename at the top of the editor widget however remains as a UNC path "\server\folder\folder\test.py" until I close and re-open the file in another way: "Y:\folder\test.py"

What do you mean by "another way"? (Sorry if this sounds dumb but I don't understand very well how UNC paths work).

I came up with a dirty hack that does the above (re-write drive letter), and I don't like it, but it does allow the file to be run with a UNC path

Ok, that's good but why don't you like it?

@athompson673
Copy link
Contributor Author

I must apologize for being a bit of a moving target... I'm partially learning as I go both what the problem is, and what could be done to fix it.

"another way":

  • file menu > open*
  • drag & drop from explorer*
  • double click file from project pane*

*unless the file is in an un-mapped network location to begin with

why don't I like it:

  • It doesn't consider network shares not mapped to a letter.
  • Filesystem is case aware but not sensitive? but not always (depending on windows registry)? I just forced .lower() for the quick hack.
  • UNC path is fine literally everywhere else but cmd.exe

Doing a bit more research, I found this serverfault post. Perhaps the command string sent to Popen could be further modified to use pushd and popd to dynamically map any un-mapped network locations, but that then brings even more questions:

  • Should we leave the drive mapped so future calls to run the program already have the drive mapped? Drive won't be unmapped until logoff or reboot..
  • If we attempt to unmap at the end of a script, what if the user runs the file multiple times concurrently in separate cmd windows?
  • Do we just blindly map the location again even if it already exists so unmapping won't impact any other running scripts? we run out in at most 25 (C is always taken..)

I kinda don't like any of these very much.... I wonder if it's most appropriate to simply figure out how to capture the error text and display it to the user "CMD doesn't support UNC path" rather than hack our way around the problem or worse (as it is now) silently fail.

@athompson673
Copy link
Contributor Author

Maybe this instead of the dirty hack? I suppose it doesn't fix the issue, but it makes it less silent...

    if os.name == 'nt':
        if wdir is not None:
            # wdir can come with / as os.sep, so we need to take care of it.
            wdir = wdir.replace('/', '\\')

        # python_exe must be quoted in case it has spaces
        cmd = f'start cmd.exe /K ""{executable}" '
        cmd += ' '.join(p_args) + '"' + ' ^&^& exit'
        try:
            popen = run_shell_command(cmd, cwd=wdir)
        except WindowsError:
            from qtpy.QtWidgets import QMessageBox
            from spyder.config.base import _
            QMessageBox.critical(None, _('Run'),
                                 _("It was not possible to run this file in "
                                   "an external terminal"),
                                 QMessageBox.Ok)
        def wait_for_error(popen):
            out, err = popen.communicate()
            if err is None: return
            print(err) #print to internal console to inform user of error. QMessageBox caused an issue...
        threading.Thread(target=wait_for_error, args=(popen,), daemon=True).start()

@ccordoba12
Copy link
Member

Ok, I like this idea better but I have one suggestion: what if instead of printing the error message in the internal console, we try to add the it to the QMessageBox message? Do you think that's feasible?

@athompson673
Copy link
Contributor Author

@ccordoba12 I haven't figured out how to use a QMessageBox in the above manner without it crashing spyder all together.. Perhaps we just try to detect a UNC path, and preempt even trying to run the file?

    if os.name == 'nt':
        if wdir is not None:
            # wdir can come with / as os.sep, so we need to take care of it.
            wdir = wdir.replace('/', '\\')
            
        if osp.splitdrive(wdir)[0].startswith("\\\\"): #UNC paths start with \\
            from qtpy.QtWidgets import QMessageBox
            from spyder.config.base import _
            QMessageBox.critical(None, _('Run'),
                                 _("External terminal does not support a UNC "
                                   "file path as the working directory."),
                                 QMessageBox.Ok)
            return

@ccordoba12
Copy link
Member

Perhaps we just try to detect a UNC path, and preempt even trying to run the file?

Nice! I really like this solution. Would you mind to open a pull request for it? If that's ok for you, please don't forget to read our Contributing guide first.

If you don't feel comfortable with that, I can do it for you, giving you the respective credit for the fix in the commit message, of course.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants