We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Reloader picks wrong module when Flask is run with the pydev debugger
This is a weird situation where the pallets/werkzeug#1416 fix to make `python -m` reloading more correct actually exposed an issue with PyDev. It rewrites `python -m flask` to `python flask` (which is clearly not correct), while Python itself rewrites it to `python /path/to/flask_entry_point.py`. Werkzeug still correctly detects that we were run as a module, but since `sys.argv[0]` is no longer a path but the module name, it incorrectly decides that there is a module named `flask.flask` in the current directory.

_Originally posted by @davidism in https://github.com/pallets/flask/issues/3297#issuecomment-510120836_

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/werkzeug/_reloader.py`
Content:
```
1 import os
2 import subprocess
3 import sys
4 import threading
5 import time
6 from itertools import chain
7 
8 from ._compat import iteritems
9 from ._compat import PY2
10 from ._compat import text_type
11 from ._internal import _log
12 
13 
14 def _iter_module_files():
15     """This iterates over all relevant Python files.  It goes through all
16     loaded files from modules, all files in folders of already loaded modules
17     as well as all files reachable through a package.
18     """
19     # The list call is necessary on Python 3 in case the module
20     # dictionary modifies during iteration.
21     for module in list(sys.modules.values()):
22         if module is None:
23             continue
24         filename = getattr(module, "__file__", None)
25         if filename:
26             if os.path.isdir(filename) and os.path.exists(
27                 os.path.join(filename, "__init__.py")
28             ):
29                 filename = os.path.join(filename, "__init__.py")
30 
31             old = None
32             while not os.path.isfile(filename):
33                 old = filename
34                 filename = os.path.dirname(filename)
35                 if filename == old:
36                     break
37             else:
38                 if filename[-4:] in (".pyc", ".pyo"):
39                     filename = filename[:-1]
40                 yield filename
41 
42 
43 def _find_observable_paths(extra_files=None):
44     """Finds all paths that should be observed."""
45     rv = set(
46         os.path.dirname(os.path.abspath(x)) if os.path.isfile(x) else os.path.abspath(x)
47         for x in sys.path
48     )
49 
50     for filename in extra_files or ():
51         rv.add(os.path.dirname(os.path.abspath(filename)))
52 
53     for module in list(sys.modules.values()):
54         fn = getattr(module, "__file__", None)
55         if fn is None:
56             continue
57         fn = os.path.abspath(fn)
58         rv.add(os.path.dirname(fn))
59 
60     return _find_common_roots(rv)
61 
62 
63 def _get_args_for_reloading():
64     """Returns the executable. This contains a workaround for windows
65     if the executable is incorrectly reported to not have the .exe
66     extension which can cause bugs on reloading.  This also contains
67     a workaround for linux where the file is executable (possibly with
68     a program other than python)
69     """
70     rv = [sys.executable]
71     py_script = os.path.abspath(sys.argv[0])
72     args = sys.argv[1:]
73     # Need to look at main module to determine how it was executed.
74     __main__ = sys.modules["__main__"]
75 
76     if __main__.__package__ is None:
77         # Executed a file, like "python app.py".
78         if os.name == "nt":
79             # Windows entry points have ".exe" extension and should be
80             # called directly.
81             if not os.path.exists(py_script) and os.path.exists(py_script + ".exe"):
82                 py_script += ".exe"
83 
84             if (
85                 os.path.splitext(rv[0])[1] == ".exe"
86                 and os.path.splitext(py_script)[1] == ".exe"
87             ):
88                 rv.pop(0)
89 
90         elif os.path.isfile(py_script) and os.access(py_script, os.X_OK):
91             # The file is marked as executable. Nix adds a wrapper that
92             # shouldn't be called with the Python executable.
93             rv.pop(0)
94 
95         rv.append(py_script)
96     else:
97         # Executed a module, like "python -m werkzeug.serving".
98         if sys.argv[0] == "-m":
99             # Flask works around previous behavior by putting
100             # "-m flask" in sys.argv.
101             # TODO remove this once Flask no longer misbehaves
102             args = sys.argv
103         else:
104             py_module = __main__.__package__
105             name = os.path.splitext(os.path.basename(py_script))[0]
106 
107             if name != "__main__":
108                 py_module += "." + name
109 
110             rv.extend(("-m", py_module.lstrip(".")))
111 
112     rv.extend(args)
113     return rv
114 
115 
116 def _find_common_roots(paths):
117     """Out of some paths it finds the common roots that need monitoring."""
118     paths = [x.split(os.path.sep) for x in paths]
119     root = {}
120     for chunks in sorted(paths, key=len, reverse=True):
121         node = root
122         for chunk in chunks:
123             node = node.setdefault(chunk, {})
124         node.clear()
125 
126     rv = set()
127 
128     def _walk(node, path):
129         for prefix, child in iteritems(node):
130             _walk(child, path + (prefix,))
131         if not node:
132             rv.add("/".join(path))
133 
134     _walk(root, ())
135     return rv
136 
137 
138 class ReloaderLoop(object):
139     name = None
140 
141     # monkeypatched by testsuite. wrapping with `staticmethod` is required in
142     # case time.sleep has been replaced by a non-c function (e.g. by
143     # `eventlet.monkey_patch`) before we get here
144     _sleep = staticmethod(time.sleep)
145 
146     def __init__(self, extra_files=None, interval=1):
147         self.extra_files = set(os.path.abspath(x) for x in extra_files or ())
148         self.interval = interval
149 
150     def run(self):
151         pass
152 
153     def restart_with_reloader(self):
154         """Spawn a new Python interpreter with the same arguments as this one,
155         but running the reloader thread.
156         """
157         while 1:
158             _log("info", " * Restarting with %s" % self.name)
159             args = _get_args_for_reloading()
160 
161             # a weird bug on windows. sometimes unicode strings end up in the
162             # environment and subprocess.call does not like this, encode them
163             # to latin1 and continue.
164             if os.name == "nt" and PY2:
165                 new_environ = {}
166                 for key, value in iteritems(os.environ):
167                     if isinstance(key, text_type):
168                         key = key.encode("iso-8859-1")
169                     if isinstance(value, text_type):
170                         value = value.encode("iso-8859-1")
171                     new_environ[key] = value
172             else:
173                 new_environ = os.environ.copy()
174 
175             new_environ["WERKZEUG_RUN_MAIN"] = "true"
176             exit_code = subprocess.call(args, env=new_environ, close_fds=False)
177             if exit_code != 3:
178                 return exit_code
179 
180     def trigger_reload(self, filename):
181         self.log_reload(filename)
182         sys.exit(3)
183 
184     def log_reload(self, filename):
185         filename = os.path.abspath(filename)
186         _log("info", " * Detected change in %r, reloading" % filename)
187 
188 
189 class StatReloaderLoop(ReloaderLoop):
190     name = "stat"
191 
192     def run(self):
193         mtimes = {}
194         while 1:
195             for filename in chain(_iter_module_files(), self.extra_files):
196                 try:
197                     mtime = os.stat(filename).st_mtime
198                 except OSError:
199                     continue
200 
201                 old_time = mtimes.get(filename)
202                 if old_time is None:
203                     mtimes[filename] = mtime
204                     continue
205                 elif mtime > old_time:
206                     self.trigger_reload(filename)
207             self._sleep(self.interval)
208 
209 
210 class WatchdogReloaderLoop(ReloaderLoop):
211     def __init__(self, *args, **kwargs):
212         ReloaderLoop.__init__(self, *args, **kwargs)
213         from watchdog.observers import Observer
214         from watchdog.events import FileSystemEventHandler
215 
216         self.observable_paths = set()
217 
218         def _check_modification(filename):
219             if filename in self.extra_files:
220                 self.trigger_reload(filename)
221             dirname = os.path.dirname(filename)
222             if dirname.startswith(tuple(self.observable_paths)):
223                 if filename.endswith((".pyc", ".pyo", ".py")):
224                     self.trigger_reload(filename)
225 
226         class _CustomHandler(FileSystemEventHandler):
227             def on_created(self, event):
228                 _check_modification(event.src_path)
229 
230             def on_modified(self, event):
231                 _check_modification(event.src_path)
232 
233             def on_moved(self, event):
234                 _check_modification(event.src_path)
235                 _check_modification(event.dest_path)
236 
237             def on_deleted(self, event):
238                 _check_modification(event.src_path)
239 
240         reloader_name = Observer.__name__.lower()
241         if reloader_name.endswith("observer"):
242             reloader_name = reloader_name[:-8]
243         reloader_name += " reloader"
244 
245         self.name = reloader_name
246 
247         self.observer_class = Observer
248         self.event_handler = _CustomHandler()
249         self.should_reload = False
250 
251     def trigger_reload(self, filename):
252         # This is called inside an event handler, which means throwing
253         # SystemExit has no effect.
254         # https://github.com/gorakhargosh/watchdog/issues/294
255         self.should_reload = True
256         self.log_reload(filename)
257 
258     def run(self):
259         watches = {}
260         observer = self.observer_class()
261         observer.start()
262 
263         try:
264             while not self.should_reload:
265                 to_delete = set(watches)
266                 paths = _find_observable_paths(self.extra_files)
267                 for path in paths:
268                     if path not in watches:
269                         try:
270                             watches[path] = observer.schedule(
271                                 self.event_handler, path, recursive=True
272                             )
273                         except OSError:
274                             # Clear this path from list of watches We don't want
275                             # the same error message showing again in the next
276                             # iteration.
277                             watches[path] = None
278                     to_delete.discard(path)
279                 for path in to_delete:
280                     watch = watches.pop(path, None)
281                     if watch is not None:
282                         observer.unschedule(watch)
283                 self.observable_paths = paths
284                 self._sleep(self.interval)
285         finally:
286             observer.stop()
287             observer.join()
288 
289         sys.exit(3)
290 
291 
292 reloader_loops = {"stat": StatReloaderLoop, "watchdog": WatchdogReloaderLoop}
293 
294 try:
295     __import__("watchdog.observers")
296 except ImportError:
297     reloader_loops["auto"] = reloader_loops["stat"]
298 else:
299     reloader_loops["auto"] = reloader_loops["watchdog"]
300 
301 
302 def ensure_echo_on():
303     """Ensure that echo mode is enabled. Some tools such as PDB disable
304     it which causes usability issues after reload."""
305     # tcgetattr will fail if stdin isn't a tty
306     if not sys.stdin.isatty():
307         return
308     try:
309         import termios
310     except ImportError:
311         return
312     attributes = termios.tcgetattr(sys.stdin)
313     if not attributes[3] & termios.ECHO:
314         attributes[3] |= termios.ECHO
315         termios.tcsetattr(sys.stdin, termios.TCSANOW, attributes)
316 
317 
318 def run_with_reloader(main_func, extra_files=None, interval=1, reloader_type="auto"):
319     """Run the given function in an independent python interpreter."""
320     import signal
321 
322     reloader = reloader_loops[reloader_type](extra_files, interval)
323     signal.signal(signal.SIGTERM, lambda *args: sys.exit(0))
324     try:
325         if os.environ.get("WERKZEUG_RUN_MAIN") == "true":
326             ensure_echo_on()
327             t = threading.Thread(target=main_func, args=())
328             t.setDaemon(True)
329             t.start()
330             reloader.run()
331         else:
332             sys.exit(reloader.restart_with_reloader())
333     except KeyboardInterrupt:
334         pass
335
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/werkzeug/_reloader.py b/src/werkzeug/_reloader.py
--- a/src/werkzeug/_reloader.py
+++ b/src/werkzeug/_reloader.py
@@ -68,13 +68,15 @@
     a program other than python)
     """
     rv = [sys.executable]
-    py_script = os.path.abspath(sys.argv[0])
+    py_script = sys.argv[0]
     args = sys.argv[1:]
     # Need to look at main module to determine how it was executed.
     __main__ = sys.modules["__main__"]
 
     if __main__.__package__ is None:
         # Executed a file, like "python app.py".
+        py_script = os.path.abspath(py_script)
+
         if os.name == "nt":
             # Windows entry points have ".exe" extension and should be
             # called directly.
@@ -101,11 +103,16 @@
             # TODO remove this once Flask no longer misbehaves
             args = sys.argv
         else:
-            py_module = __main__.__package__
-            name = os.path.splitext(os.path.basename(py_script))[0]
+            if os.path.isfile(py_script):
+                # Rewritten by Python from "-m script" to "/path/to/script.py".
+                py_module = __main__.__package__
+                name = os.path.splitext(os.path.basename(py_script))[0]
 
-            if name != "__main__":
-                py_module += "." + name
+                if name != "__main__":
+                    py_module += "." + name
+            else:
+                # Incorrectly rewritten by pydevd debugger from "-m script" to "script".
+                py_module = py_script
 
             rv.extend(("-m", py_module.lstrip(".")))

{"golden_diff": "diff --git a/src/werkzeug/_reloader.py b/src/werkzeug/_reloader.py\n--- a/src/werkzeug/_reloader.py\n+++ b/src/werkzeug/_reloader.py\n@@ -68,13 +68,15 @@\n     a program other than python)\n     \"\"\"\n     rv = [sys.executable]\n-    py_script = os.path.abspath(sys.argv[0])\n+    py_script = sys.argv[0]\n     args = sys.argv[1:]\n     # Need to look at main module to determine how it was executed.\n     __main__ = sys.modules[\"__main__\"]\n \n     if __main__.__package__ is None:\n         # Executed a file, like \"python app.py\".\n+        py_script = os.path.abspath(py_script)\n+\n         if os.name == \"nt\":\n             # Windows entry points have \".exe\" extension and should be\n             # called directly.\n@@ -101,11 +103,16 @@\n             # TODO remove this once Flask no longer misbehaves\n             args = sys.argv\n         else:\n-            py_module = __main__.__package__\n-            name = os.path.splitext(os.path.basename(py_script))[0]\n+            if os.path.isfile(py_script):\n+                # Rewritten by Python from \"-m script\" to \"/path/to/script.py\".\n+                py_module = __main__.__package__\n+                name = os.path.splitext(os.path.basename(py_script))[0]\n \n-            if name != \"__main__\":\n-                py_module += \".\" + name\n+                if name != \"__main__\":\n+                    py_module += \".\" + name\n+            else:\n+                # Incorrectly rewritten by pydevd debugger from \"-m script\" to \"script\".\n+                py_module = py_script\n \n             rv.extend((\"-m\", py_module.lstrip(\".\")))\n", "issue": "Reloader picks wrong module when Flask is run with the pydev debugger\nThis is a weird situation where the pallets/werkzeug#1416 fix to make `python -m` reloading more correct actually exposed an issue with PyDev. It rewrites `python -m flask` to `python flask` (which is clearly not correct), while Python itself rewrites it to `python /path/to/flask_entry_point.py`. Werkzeug still correctly detects that we were run as a module, but since `sys.argv[0]` is no longer a path but the module name, it incorrectly decides that there is a module named `flask.flask` in the current directory.\r\n\r\n_Originally posted by @davidism in https://github.com/pallets/flask/issues/3297#issuecomment-510120836_\n", "before_files": [{"content": "import os\nimport subprocess\nimport sys\nimport threading\nimport time\nfrom itertools import chain\n\nfrom ._compat import iteritems\nfrom ._compat import PY2\nfrom ._compat import text_type\nfrom ._internal import _log\n\n\ndef _iter_module_files():\n    \"\"\"This iterates over all relevant Python files.  It goes through all\n    loaded files from modules, all files in folders of already loaded modules\n    as well as all files reachable through a package.\n    \"\"\"\n    # The list call is necessary on Python 3 in case the module\n    # dictionary modifies during iteration.\n    for module in list(sys.modules.values()):\n        if module is None:\n            continue\n        filename = getattr(module, \"__file__\", None)\n        if filename:\n            if os.path.isdir(filename) and os.path.exists(\n                os.path.join(filename, \"__init__.py\")\n            ):\n                filename = os.path.join(filename, \"__init__.py\")\n\n            old = None\n            while not os.path.isfile(filename):\n                old = filename\n                filename = os.path.dirname(filename)\n                if filename == old:\n                    break\n            else:\n                if filename[-4:] in (\".pyc\", \".pyo\"):\n                    filename = filename[:-1]\n                yield filename\n\n\ndef _find_observable_paths(extra_files=None):\n    \"\"\"Finds all paths that should be observed.\"\"\"\n    rv = set(\n        os.path.dirname(os.path.abspath(x)) if os.path.isfile(x) else os.path.abspath(x)\n        for x in sys.path\n    )\n\n    for filename in extra_files or ():\n        rv.add(os.path.dirname(os.path.abspath(filename)))\n\n    for module in list(sys.modules.values()):\n        fn = getattr(module, \"__file__\", None)\n        if fn is None:\n            continue\n        fn = os.path.abspath(fn)\n        rv.add(os.path.dirname(fn))\n\n    return _find_common_roots(rv)\n\n\ndef _get_args_for_reloading():\n    \"\"\"Returns the executable. This contains a workaround for windows\n    if the executable is incorrectly reported to not have the .exe\n    extension which can cause bugs on reloading.  This also contains\n    a workaround for linux where the file is executable (possibly with\n    a program other than python)\n    \"\"\"\n    rv = [sys.executable]\n    py_script = os.path.abspath(sys.argv[0])\n    args = sys.argv[1:]\n    # Need to look at main module to determine how it was executed.\n    __main__ = sys.modules[\"__main__\"]\n\n    if __main__.__package__ is None:\n        # Executed a file, like \"python app.py\".\n        if os.name == \"nt\":\n            # Windows entry points have \".exe\" extension and should be\n            # called directly.\n            if not os.path.exists(py_script) and os.path.exists(py_script + \".exe\"):\n                py_script += \".exe\"\n\n            if (\n                os.path.splitext(rv[0])[1] == \".exe\"\n                and os.path.splitext(py_script)[1] == \".exe\"\n            ):\n                rv.pop(0)\n\n        elif os.path.isfile(py_script) and os.access(py_script, os.X_OK):\n            # The file is marked as executable. Nix adds a wrapper that\n            # shouldn't be called with the Python executable.\n            rv.pop(0)\n\n        rv.append(py_script)\n    else:\n        # Executed a module, like \"python -m werkzeug.serving\".\n        if sys.argv[0] == \"-m\":\n            # Flask works around previous behavior by putting\n            # \"-m flask\" in sys.argv.\n            # TODO remove this once Flask no longer misbehaves\n            args = sys.argv\n        else:\n            py_module = __main__.__package__\n            name = os.path.splitext(os.path.basename(py_script))[0]\n\n            if name != \"__main__\":\n                py_module += \".\" + name\n\n            rv.extend((\"-m\", py_module.lstrip(\".\")))\n\n    rv.extend(args)\n    return rv\n\n\ndef _find_common_roots(paths):\n    \"\"\"Out of some paths it finds the common roots that need monitoring.\"\"\"\n    paths = [x.split(os.path.sep) for x in paths]\n    root = {}\n    for chunks in sorted(paths, key=len, reverse=True):\n        node = root\n        for chunk in chunks:\n            node = node.setdefault(chunk, {})\n        node.clear()\n\n    rv = set()\n\n    def _walk(node, path):\n        for prefix, child in iteritems(node):\n            _walk(child, path + (prefix,))\n        if not node:\n            rv.add(\"/\".join(path))\n\n    _walk(root, ())\n    return rv\n\n\nclass ReloaderLoop(object):\n    name = None\n\n    # monkeypatched by testsuite. wrapping with `staticmethod` is required in\n    # case time.sleep has been replaced by a non-c function (e.g. by\n    # `eventlet.monkey_patch`) before we get here\n    _sleep = staticmethod(time.sleep)\n\n    def __init__(self, extra_files=None, interval=1):\n        self.extra_files = set(os.path.abspath(x) for x in extra_files or ())\n        self.interval = interval\n\n    def run(self):\n        pass\n\n    def restart_with_reloader(self):\n        \"\"\"Spawn a new Python interpreter with the same arguments as this one,\n        but running the reloader thread.\n        \"\"\"\n        while 1:\n            _log(\"info\", \" * Restarting with %s\" % self.name)\n            args = _get_args_for_reloading()\n\n            # a weird bug on windows. sometimes unicode strings end up in the\n            # environment and subprocess.call does not like this, encode them\n            # to latin1 and continue.\n            if os.name == \"nt\" and PY2:\n                new_environ = {}\n                for key, value in iteritems(os.environ):\n                    if isinstance(key, text_type):\n                        key = key.encode(\"iso-8859-1\")\n                    if isinstance(value, text_type):\n                        value = value.encode(\"iso-8859-1\")\n                    new_environ[key] = value\n            else:\n                new_environ = os.environ.copy()\n\n            new_environ[\"WERKZEUG_RUN_MAIN\"] = \"true\"\n            exit_code = subprocess.call(args, env=new_environ, close_fds=False)\n            if exit_code != 3:\n                return exit_code\n\n    def trigger_reload(self, filename):\n        self.log_reload(filename)\n        sys.exit(3)\n\n    def log_reload(self, filename):\n        filename = os.path.abspath(filename)\n        _log(\"info\", \" * Detected change in %r, reloading\" % filename)\n\n\nclass StatReloaderLoop(ReloaderLoop):\n    name = \"stat\"\n\n    def run(self):\n        mtimes = {}\n        while 1:\n            for filename in chain(_iter_module_files(), self.extra_files):\n                try:\n                    mtime = os.stat(filename).st_mtime\n                except OSError:\n                    continue\n\n                old_time = mtimes.get(filename)\n                if old_time is None:\n                    mtimes[filename] = mtime\n                    continue\n                elif mtime > old_time:\n                    self.trigger_reload(filename)\n            self._sleep(self.interval)\n\n\nclass WatchdogReloaderLoop(ReloaderLoop):\n    def __init__(self, *args, **kwargs):\n        ReloaderLoop.__init__(self, *args, **kwargs)\n        from watchdog.observers import Observer\n        from watchdog.events import FileSystemEventHandler\n\n        self.observable_paths = set()\n\n        def _check_modification(filename):\n            if filename in self.extra_files:\n                self.trigger_reload(filename)\n            dirname = os.path.dirname(filename)\n            if dirname.startswith(tuple(self.observable_paths)):\n                if filename.endswith((\".pyc\", \".pyo\", \".py\")):\n                    self.trigger_reload(filename)\n\n        class _CustomHandler(FileSystemEventHandler):\n            def on_created(self, event):\n                _check_modification(event.src_path)\n\n            def on_modified(self, event):\n                _check_modification(event.src_path)\n\n            def on_moved(self, event):\n                _check_modification(event.src_path)\n                _check_modification(event.dest_path)\n\n            def on_deleted(self, event):\n                _check_modification(event.src_path)\n\n        reloader_name = Observer.__name__.lower()\n        if reloader_name.endswith(\"observer\"):\n            reloader_name = reloader_name[:-8]\n        reloader_name += \" reloader\"\n\n        self.name = reloader_name\n\n        self.observer_class = Observer\n        self.event_handler = _CustomHandler()\n        self.should_reload = False\n\n    def trigger_reload(self, filename):\n        # This is called inside an event handler, which means throwing\n        # SystemExit has no effect.\n        # https://github.com/gorakhargosh/watchdog/issues/294\n        self.should_reload = True\n        self.log_reload(filename)\n\n    def run(self):\n        watches = {}\n        observer = self.observer_class()\n        observer.start()\n\n        try:\n            while not self.should_reload:\n                to_delete = set(watches)\n                paths = _find_observable_paths(self.extra_files)\n                for path in paths:\n                    if path not in watches:\n                        try:\n                            watches[path] = observer.schedule(\n                                self.event_handler, path, recursive=True\n                            )\n                        except OSError:\n                            # Clear this path from list of watches We don't want\n                            # the same error message showing again in the next\n                            # iteration.\n                            watches[path] = None\n                    to_delete.discard(path)\n                for path in to_delete:\n                    watch = watches.pop(path, None)\n                    if watch is not None:\n                        observer.unschedule(watch)\n                self.observable_paths = paths\n                self._sleep(self.interval)\n        finally:\n            observer.stop()\n            observer.join()\n\n        sys.exit(3)\n\n\nreloader_loops = {\"stat\": StatReloaderLoop, \"watchdog\": WatchdogReloaderLoop}\n\ntry:\n    __import__(\"watchdog.observers\")\nexcept ImportError:\n    reloader_loops[\"auto\"] = reloader_loops[\"stat\"]\nelse:\n    reloader_loops[\"auto\"] = reloader_loops[\"watchdog\"]\n\n\ndef ensure_echo_on():\n    \"\"\"Ensure that echo mode is enabled. Some tools such as PDB disable\n    it which causes usability issues after reload.\"\"\"\n    # tcgetattr will fail if stdin isn't a tty\n    if not sys.stdin.isatty():\n        return\n    try:\n        import termios\n    except ImportError:\n        return\n    attributes = termios.tcgetattr(sys.stdin)\n    if not attributes[3] & termios.ECHO:\n        attributes[3] |= termios.ECHO\n        termios.tcsetattr(sys.stdin, termios.TCSANOW, attributes)\n\n\ndef run_with_reloader(main_func, extra_files=None, interval=1, reloader_type=\"auto\"):\n    \"\"\"Run the given function in an independent python interpreter.\"\"\"\n    import signal\n\n    reloader = reloader_loops[reloader_type](extra_files, interval)\n    signal.signal(signal.SIGTERM, lambda *args: sys.exit(0))\n    try:\n        if os.environ.get(\"WERKZEUG_RUN_MAIN\") == \"true\":\n            ensure_echo_on()\n            t = threading.Thread(target=main_func, args=())\n            t.setDaemon(True)\n            t.start()\n            reloader.run()\n        else:\n            sys.exit(reloader.restart_with_reloader())\n    except KeyboardInterrupt:\n        pass\n", "path": "src/werkzeug/_reloader.py"}], "after_files": [{"content": "import os\nimport subprocess\nimport sys\nimport threading\nimport time\nfrom itertools import chain\n\nfrom ._compat import iteritems\nfrom ._compat import PY2\nfrom ._compat import text_type\nfrom ._internal import _log\n\n\ndef _iter_module_files():\n    \"\"\"This iterates over all relevant Python files.  It goes through all\n    loaded files from modules, all files in folders of already loaded modules\n    as well as all files reachable through a package.\n    \"\"\"\n    # The list call is necessary on Python 3 in case the module\n    # dictionary modifies during iteration.\n    for module in list(sys.modules.values()):\n        if module is None:\n            continue\n        filename = getattr(module, \"__file__\", None)\n        if filename:\n            if os.path.isdir(filename) and os.path.exists(\n                os.path.join(filename, \"__init__.py\")\n            ):\n                filename = os.path.join(filename, \"__init__.py\")\n\n            old = None\n            while not os.path.isfile(filename):\n                old = filename\n                filename = os.path.dirname(filename)\n                if filename == old:\n                    break\n            else:\n                if filename[-4:] in (\".pyc\", \".pyo\"):\n                    filename = filename[:-1]\n                yield filename\n\n\ndef _find_observable_paths(extra_files=None):\n    \"\"\"Finds all paths that should be observed.\"\"\"\n    rv = set(\n        os.path.dirname(os.path.abspath(x)) if os.path.isfile(x) else os.path.abspath(x)\n        for x in sys.path\n    )\n\n    for filename in extra_files or ():\n        rv.add(os.path.dirname(os.path.abspath(filename)))\n\n    for module in list(sys.modules.values()):\n        fn = getattr(module, \"__file__\", None)\n        if fn is None:\n            continue\n        fn = os.path.abspath(fn)\n        rv.add(os.path.dirname(fn))\n\n    return _find_common_roots(rv)\n\n\ndef _get_args_for_reloading():\n    \"\"\"Returns the executable. This contains a workaround for windows\n    if the executable is incorrectly reported to not have the .exe\n    extension which can cause bugs on reloading.  This also contains\n    a workaround for linux where the file is executable (possibly with\n    a program other than python)\n    \"\"\"\n    rv = [sys.executable]\n    py_script = sys.argv[0]\n    args = sys.argv[1:]\n    # Need to look at main module to determine how it was executed.\n    __main__ = sys.modules[\"__main__\"]\n\n    if __main__.__package__ is None:\n        # Executed a file, like \"python app.py\".\n        py_script = os.path.abspath(py_script)\n\n        if os.name == \"nt\":\n            # Windows entry points have \".exe\" extension and should be\n            # called directly.\n            if not os.path.exists(py_script) and os.path.exists(py_script + \".exe\"):\n                py_script += \".exe\"\n\n            if (\n                os.path.splitext(rv[0])[1] == \".exe\"\n                and os.path.splitext(py_script)[1] == \".exe\"\n            ):\n                rv.pop(0)\n\n        elif os.path.isfile(py_script) and os.access(py_script, os.X_OK):\n            # The file is marked as executable. Nix adds a wrapper that\n            # shouldn't be called with the Python executable.\n            rv.pop(0)\n\n        rv.append(py_script)\n    else:\n        # Executed a module, like \"python -m werkzeug.serving\".\n        if sys.argv[0] == \"-m\":\n            # Flask works around previous behavior by putting\n            # \"-m flask\" in sys.argv.\n            # TODO remove this once Flask no longer misbehaves\n            args = sys.argv\n        else:\n            if os.path.isfile(py_script):\n                # Rewritten by Python from \"-m script\" to \"/path/to/script.py\".\n                py_module = __main__.__package__\n                name = os.path.splitext(os.path.basename(py_script))[0]\n\n                if name != \"__main__\":\n                    py_module += \".\" + name\n            else:\n                # Incorrectly rewritten by pydevd debugger from \"-m script\" to \"script\".\n                py_module = py_script\n\n            rv.extend((\"-m\", py_module.lstrip(\".\")))\n\n    rv.extend(args)\n    return rv\n\n\ndef _find_common_roots(paths):\n    \"\"\"Out of some paths it finds the common roots that need monitoring.\"\"\"\n    paths = [x.split(os.path.sep) for x in paths]\n    root = {}\n    for chunks in sorted(paths, key=len, reverse=True):\n        node = root\n        for chunk in chunks:\n            node = node.setdefault(chunk, {})\n        node.clear()\n\n    rv = set()\n\n    def _walk(node, path):\n        for prefix, child in iteritems(node):\n            _walk(child, path + (prefix,))\n        if not node:\n            rv.add(\"/\".join(path))\n\n    _walk(root, ())\n    return rv\n\n\nclass ReloaderLoop(object):\n    name = None\n\n    # monkeypatched by testsuite. wrapping with `staticmethod` is required in\n    # case time.sleep has been replaced by a non-c function (e.g. by\n    # `eventlet.monkey_patch`) before we get here\n    _sleep = staticmethod(time.sleep)\n\n    def __init__(self, extra_files=None, interval=1):\n        self.extra_files = set(os.path.abspath(x) for x in extra_files or ())\n        self.interval = interval\n\n    def run(self):\n        pass\n\n    def restart_with_reloader(self):\n        \"\"\"Spawn a new Python interpreter with the same arguments as this one,\n        but running the reloader thread.\n        \"\"\"\n        while 1:\n            _log(\"info\", \" * Restarting with %s\" % self.name)\n            args = _get_args_for_reloading()\n\n            # a weird bug on windows. sometimes unicode strings end up in the\n            # environment and subprocess.call does not like this, encode them\n            # to latin1 and continue.\n            if os.name == \"nt\" and PY2:\n                new_environ = {}\n                for key, value in iteritems(os.environ):\n                    if isinstance(key, text_type):\n                        key = key.encode(\"iso-8859-1\")\n                    if isinstance(value, text_type):\n                        value = value.encode(\"iso-8859-1\")\n                    new_environ[key] = value\n            else:\n                new_environ = os.environ.copy()\n\n            new_environ[\"WERKZEUG_RUN_MAIN\"] = \"true\"\n            exit_code = subprocess.call(args, env=new_environ, close_fds=False)\n            if exit_code != 3:\n                return exit_code\n\n    def trigger_reload(self, filename):\n        self.log_reload(filename)\n        sys.exit(3)\n\n    def log_reload(self, filename):\n        filename = os.path.abspath(filename)\n        _log(\"info\", \" * Detected change in %r, reloading\" % filename)\n\n\nclass StatReloaderLoop(ReloaderLoop):\n    name = \"stat\"\n\n    def run(self):\n        mtimes = {}\n        while 1:\n            for filename in chain(_iter_module_files(), self.extra_files):\n                try:\n                    mtime = os.stat(filename).st_mtime\n                except OSError:\n                    continue\n\n                old_time = mtimes.get(filename)\n                if old_time is None:\n                    mtimes[filename] = mtime\n                    continue\n                elif mtime > old_time:\n                    self.trigger_reload(filename)\n            self._sleep(self.interval)\n\n\nclass WatchdogReloaderLoop(ReloaderLoop):\n    def __init__(self, *args, **kwargs):\n        ReloaderLoop.__init__(self, *args, **kwargs)\n        from watchdog.observers import Observer\n        from watchdog.events import FileSystemEventHandler\n\n        self.observable_paths = set()\n\n        def _check_modification(filename):\n            if filename in self.extra_files:\n                self.trigger_reload(filename)\n            dirname = os.path.dirname(filename)\n            if dirname.startswith(tuple(self.observable_paths)):\n                if filename.endswith((\".pyc\", \".pyo\", \".py\")):\n                    self.trigger_reload(filename)\n\n        class _CustomHandler(FileSystemEventHandler):\n            def on_created(self, event):\n                _check_modification(event.src_path)\n\n            def on_modified(self, event):\n                _check_modification(event.src_path)\n\n            def on_moved(self, event):\n                _check_modification(event.src_path)\n                _check_modification(event.dest_path)\n\n            def on_deleted(self, event):\n                _check_modification(event.src_path)\n\n        reloader_name = Observer.__name__.lower()\n        if reloader_name.endswith(\"observer\"):\n            reloader_name = reloader_name[:-8]\n        reloader_name += \" reloader\"\n\n        self.name = reloader_name\n\n        self.observer_class = Observer\n        self.event_handler = _CustomHandler()\n        self.should_reload = False\n\n    def trigger_reload(self, filename):\n        # This is called inside an event handler, which means throwing\n        # SystemExit has no effect.\n        # https://github.com/gorakhargosh/watchdog/issues/294\n        self.should_reload = True\n        self.log_reload(filename)\n\n    def run(self):\n        watches = {}\n        observer = self.observer_class()\n        observer.start()\n\n        try:\n            while not self.should_reload:\n                to_delete = set(watches)\n                paths = _find_observable_paths(self.extra_files)\n                for path in paths:\n                    if path not in watches:\n                        try:\n                            watches[path] = observer.schedule(\n                                self.event_handler, path, recursive=True\n                            )\n                        except OSError:\n                            # Clear this path from list of watches We don't want\n                            # the same error message showing again in the next\n                            # iteration.\n                            watches[path] = None\n                    to_delete.discard(path)\n                for path in to_delete:\n                    watch = watches.pop(path, None)\n                    if watch is not None:\n                        observer.unschedule(watch)\n                self.observable_paths = paths\n                self._sleep(self.interval)\n        finally:\n            observer.stop()\n            observer.join()\n\n        sys.exit(3)\n\n\nreloader_loops = {\"stat\": StatReloaderLoop, \"watchdog\": WatchdogReloaderLoop}\n\ntry:\n    __import__(\"watchdog.observers\")\nexcept ImportError:\n    reloader_loops[\"auto\"] = reloader_loops[\"stat\"]\nelse:\n    reloader_loops[\"auto\"] = reloader_loops[\"watchdog\"]\n\n\ndef ensure_echo_on():\n    \"\"\"Ensure that echo mode is enabled. Some tools such as PDB disable\n    it which causes usability issues after reload.\"\"\"\n    # tcgetattr will fail if stdin isn't a tty\n    if not sys.stdin.isatty():\n        return\n    try:\n        import termios\n    except ImportError:\n        return\n    attributes = termios.tcgetattr(sys.stdin)\n    if not attributes[3] & termios.ECHO:\n        attributes[3] |= termios.ECHO\n        termios.tcsetattr(sys.stdin, termios.TCSANOW, attributes)\n\n\ndef run_with_reloader(main_func, extra_files=None, interval=1, reloader_type=\"auto\"):\n    \"\"\"Run the given function in an independent python interpreter.\"\"\"\n    import signal\n\n    reloader = reloader_loops[reloader_type](extra_files, interval)\n    signal.signal(signal.SIGTERM, lambda *args: sys.exit(0))\n    try:\n        if os.environ.get(\"WERKZEUG_RUN_MAIN\") == \"true\":\n            ensure_echo_on()\n            t = threading.Thread(target=main_func, args=())\n            t.setDaemon(True)\n            t.start()\n            reloader.run()\n        else:\n            sys.exit(reloader.restart_with_reloader())\n    except KeyboardInterrupt:\n        pass\n", "path": "src/werkzeug/_reloader.py"}]}