Repository: Pylons/pyramid

Issue:
pserve --reload does not work on windows
Things work fine with pserve, but the process fails to fork, presumably because it's using the wrong executable name.

```
PS C:\Users\michael\Desktop\work\pyramid> .\Scripts\pserve.exe .\foo\development.ini
Starting server in PID 2436.
serving on http://0.0.0.0:6543
Exiting (-v to see traceback)
PS C:\Users\michael\Desktop\work\pyramid>
PS C:\Users\michael\Desktop\work\pyramid>
PS C:\Users\michael\Desktop\work\pyramid> .\Scripts\pserve.exe .\foo\development.ini --reload
Starting subprocess with file monitor
c:\users\michael\desktop\work\pyramid\scripts\python.exe: can't open file 'C:\Users\michael\Desktop\work\pyramid\Scripts
\pserve': [Errno 2] No such file or directory
```



Discussion:
I wonder what `sys.executable` is set to here:

https://github.com/Pylons/pyramid/blob/master/pyramid/scripts/pserve.py#L576

based on your error it seems to be set to `python.exe` not `pserve.exe`.

Then there is this:

https://github.com/Pylons/pyramid/blob/master/pyramid/scripts/pserve.py#L411

Which specifically mentions fixing path issues on Windows...

I can confirm that this fix works.

``` diff
diff --git a/pyramid/scripts/pserve.py b/pyramid/scripts/pserve.py
index 2695313..1d5995f 100644
--- a/pyramid/scripts/pserve.py
+++ b/pyramid/scripts/pserve.py
@@ -386,6 +386,17 @@ class PServeCommand(object):
         arg = win32api.GetShortPathName(arg)
         return arg

+    def fix_script_name(self, name): # pragma: no cover
+        """
+        There's an issue on Windows when running the executable from
+        a console_script causing the script name (sys.argv[0]) to
+        not end with .exe or .py and thus cannot be run via popen.
+        """
+        if sys.platform == 'win32':
+            if not name.endswith('.exe') and not name.endswith('.py'):
+                name += '.exe'
+        return name
+
     def daemonize(self): # pragma: no cover
         pid = live_pidfile(self.options.pid_file)
         if pid:
@@ -531,7 +542,8 @@ class PServeCommand(object):
             else:
                 self.out('Starting subprocess with monitor parent')
         while 1:
-            args = [self.quote_first_command_arg(sys.executable)] + sys.argv
+            script_exe = self.fix_script_name(sys.argv[0])
+            args = [self.quote_first_command_arg(sys.executable), script_exe] + sys.argv[1:]
             new_environ = os.environ.copy()
             if reloader:
                 new_environ[self._reloader_environ_key] = 'true'
```

Alternatively we could set `shell=True` but that is historically discouraged in docs I read because the shell is user-defined on most non-windows platforms. I confirmed that works as well.


Resolving patch:
diff --git a/pyramid/scripts/pserve.py b/pyramid/scripts/pserve.py
--- a/pyramid/scripts/pserve.py
+++ b/pyramid/scripts/pserve.py
@@ -428,6 +428,19 @@ def quote_first_command_arg(self, arg): # pragma: no cover
         arg = win32api.GetShortPathName(arg)
         return arg
 
+    def find_script_path(self, name): # pragma: no cover
+        """
+        Return the path to the script being invoked by the python interpreter.
+
+        There's an issue on Windows when running the executable from
+        a console_script causing the script name (sys.argv[0]) to
+        not end with .exe or .py and thus cannot be run via popen.
+        """
+        if sys.platform == 'win32':
+            if not name.endswith('.exe') and not name.endswith('.py'):
+                name += '.exe'
+        return name
+
     def daemonize(self): # pragma: no cover
         pid = live_pidfile(self.options.pid_file)
         if pid:
@@ -573,7 +586,10 @@ def restart_with_monitor(self, reloader=False): # pragma: no cover
             else:
                 self.out('Starting subprocess with monitor parent')
         while 1:
-            args = [self.quote_first_command_arg(sys.executable)] + sys.argv
+            args = [
+                self.quote_first_command_arg(sys.executable),
+                self.find_script_path(sys.argv[0]),
+            ] + sys.argv[1:]
             new_environ = os.environ.copy()
             if reloader:
                 new_environ[self._reloader_environ_key] = 'true'


Test patch: