Repository: pallets/werkzeug

Issue:
Reloader is breaking the execution if using Poetry scripts
The Flask reloader is apparently using the executed command instead of the actual Python package. When I try running with Poetry scripts, it throws an error (only if the reloader is enabled)

To replicate the behavior you can create a new Poetry Python package, install Flask and create the following Poetry script:
```toml
[tool.poetry.scripts]
dev = 'my_package.main:run'
```
(as you can imagine, you need to have a `run` function inside a file called `main.py` within a folder called `my_package` that will create the app and run it)

Now, you can set `FLASK_DEBUG=0` and run it with `poetry run dev`. It will work (as expected).

After this, you can set `FLASK_DEBUG=1` and run the same command, it will fail saying that it wasn't able to find the `dev` file. I've explored it a little bit, and the problem isn't the debugger, but the reloader (if you launch with the debugger, but without the reloader it works)

It seems the reloader somehow uses the executed command (`dev`) as the expected Python file to be used upon reloading and, because of that, it can't find the file and throws an error.

Environment:

- Python version: 3.10
- Flask version: 2.2.2



Discussion:
If I modify Werkzeug's reloader to print out `sys.argv` and `sys.orig_argv`, it shows this:

```
sys.argv = ['dev']
sys.orig_argv = ['/home/david/.cache/pypoetry/virtualenvs/hello-y1FJtfO2-py3.10/bin/python', '-c', "import sys; from importlib import import_module; sys.argv = ['dev']; sys.exit(import_module('hello').run())"]
```

This points to an issue with Poetry, it is breaking the [documented behavior of `sys.argv`](https://docs.python.org/3/library/sys.html#sys.argv) by setting `sys.argv = ["dev"]`; it should either set it to `["-c"]` or to the filename of the module it imported. **Please report that to Poetry.**

That said, Werkzeug still wouldn't support this, as the `python -c 'code'` form of invoking Python does not put enough information in `sys.argv` to recreate the command. I was already looking at [`sys.orig_argv`](https://docs.python.org/3/library/sys.html#sys.orig_argv), but that was only added in Python 3.10.

Since you're using Flask, you should use the `flask` command to run the development server, rather than creating your own entry point.
I opened https://github.com/pallets/werkzeug/issues/2589 to better describe what I was working on already. It will fix this issue as well. The `sys.argv` issue I described above **should still be reported to Poetry**.

Resolving patch:
diff --git a/src/werkzeug/_reloader.py b/src/werkzeug/_reloader.py
--- a/src/werkzeug/_reloader.py
+++ b/src/werkzeug/_reloader.py
@@ -166,6 +166,11 @@ def _get_args_for_reloading() -> t.List[str]:
     """Determine how the script was executed, and return the args needed
     to execute it again in a new process.
     """
+    if sys.version_info >= (3, 10):
+        # sys.orig_argv, added in Python 3.10, contains the exact args used to invoke
+        # Python. Still replace argv[0] with sys.executable for accuracy.
+        return [sys.executable, *sys.orig_argv[1:]]
+
     rv = [sys.executable]
     py_script = sys.argv[0]
     args = sys.argv[1:]


Test patch:
diff --git a/tests/test_serving.py b/tests/test_serving.py
--- a/tests/test_serving.py
+++ b/tests/test_serving.py
@@ -115,6 +115,7 @@ def test_reloader_sys_path(tmp_path, dev_server, reloader_type):
     assert client.request().status == 200
 
 
+@pytest.mark.skipif(sys.version_info >= (3, 10), reason="not needed on >= 3.10")
 def test_windows_get_args_for_reloading(monkeypatch, tmp_path):
     argv = [str(tmp_path / "test.exe"), "run"]
     monkeypatch.setattr("sys.executable", str(tmp_path / "python.exe"))