We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
mac thinks that napari is named "__main__.py" in bundled app
## 🐛 Bug

My mac seems to think that napari is named "__main__.py" in bundled app

## To Reproduce

Steps to reproduce the behavior:

1. Launch napari bundled app on mac
2. Click "napari" on menu bar
3. See the menu items "Hide __main__.py" and "Close __main__.py"

![image](https://user-images.githubusercontent.com/1245615/110528081-f6626e00-80d4-11eb-867b-2b3955d13957.png)

## Expected behavior

menu items include "Hide napari" and "Close napari", similar to Chrome...

<!-- A clear and concise description of what you expected to happen. -->
![image](https://user-images.githubusercontent.com/1245615/110528760-bc459c00-80d5-11eb-8ca8-0f04c3247ea1.png)

## Environment

napari: 0.4.6
Platform: macOS-10.15.7-x86_64-i386-64bit
System: MacOS 10.15.7
Python: 3.8.7 (default, Jan 2 2021, 04:16:43) [Clang 11.0.0 (clang-1100.0.33.17)]
Qt: 5.15.2
PySide2: 5.15.2
NumPy: 1.19.3
SciPy: 1.6.1
Dask: 2021.03.0
VisPy: 0.6.6

OpenGL:
- GL version: 2.1 ATI-3.10.19
- MAX_TEXTURE_SIZE: 16384

Screens:
- screen 1: resolution 1792x1120, scale 2.0
- screen 2: resolution 2560x1440, scale 1.0

Plugins:
- affinder: 0.1.0
- aicsimageio: 0.2.0
- aicsimageio_delayed: 0.2.0
- brainreg: 0.2.3
- brainreg_standard: 0.2.3
- cellfinder: 0.2.1
- console: 0.0.3
- napari-hdf5-labels-io: 0.2.dev1
- ndtiffs: 0.1.1
- svg: 0.1.4


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `bundle.py`
Content:
```
1 import configparser
2 import os
3 import re
4 import shutil
5 import subprocess
6 import sys
7 import time
8 from contextlib import contextmanager
9 
10 import tomlkit
11 
12 APP = 'napari'
13 
14 # EXTRA_REQS will be added to the bundle, in addition to those specified in
15 # setup.cfg.  To add additional packages to the bundle, or to override any of
16 # the packages listed here or in `setup.cfg, use the `--add` command line
17 # argument with a series of "pip install" style strings when running this file.
18 # For example, the following will ADD ome-zarr, and CHANGE the version of
19 # PySide2:
20 # python bundle.py --add 'PySide2==5.15.0' 'ome-zarr'
21 
22 EXTRA_REQS = [
23     "pip",
24     "PySide2==5.15.2",
25     "scikit-image",
26     "zarr",
27     "pims",
28     "numpy==1.19.3",
29 ]
30 
31 WINDOWS = os.name == 'nt'
32 MACOS = sys.platform == 'darwin'
33 LINUX = sys.platform.startswith("linux")
34 HERE = os.path.abspath(os.path.dirname(__file__))
35 PYPROJECT_TOML = os.path.join(HERE, 'pyproject.toml')
36 SETUP_CFG = os.path.join(HERE, 'setup.cfg')
37 
38 if WINDOWS:
39     BUILD_DIR = os.path.join(HERE, 'windows')
40 elif LINUX:
41     BUILD_DIR = os.path.join(HERE, 'linux')
42 elif MACOS:
43     BUILD_DIR = os.path.join(HERE, 'macOS')
44     APP_DIR = os.path.join(BUILD_DIR, APP, f'{APP}.app')
45 
46 
47 with open(os.path.join(HERE, "napari", "_version.py")) as f:
48     match = re.search(r'version\s?=\s?\'([^\']+)', f.read())
49     if match:
50         VERSION = match.groups()[0].split('+')[0]
51 
52 
53 @contextmanager
54 def patched_toml():
55     parser = configparser.ConfigParser()
56     parser.read(SETUP_CFG)
57     requirements = parser.get("options", "install_requires").splitlines()
58     requirements = [r.split('#')[0].strip() for r in requirements if r]
59 
60     with open(PYPROJECT_TOML) as f:
61         original_toml = f.read()
62 
63     toml = tomlkit.parse(original_toml)
64 
65     # parse command line arguments
66     if '--add' in sys.argv:
67         for item in sys.argv[sys.argv.index('--add') + 1 :]:
68             if item.startswith('-'):
69                 break
70             EXTRA_REQS.append(item)
71 
72     for item in EXTRA_REQS:
73         _base = re.split('<|>|=', item, maxsplit=1)[0]
74         for r in requirements:
75             if r.startswith(_base):
76                 requirements.remove(r)
77                 break
78         if _base.lower().startswith('pyqt5'):
79             try:
80                 i = next(x for x in requirements if x.startswith('PySide'))
81                 requirements.remove(i)
82             except StopIteration:
83                 pass
84 
85     requirements += EXTRA_REQS
86 
87     toml['tool']['briefcase']['app'][APP]['requires'] = requirements
88     toml['tool']['briefcase']['version'] = VERSION
89 
90     print("patching pyroject.toml to version: ", VERSION)
91     print(
92         "patching pyroject.toml requirements to : \n",
93         "\n".join(toml['tool']['briefcase']['app'][APP]['requires']),
94     )
95     with open(PYPROJECT_TOML, 'w') as f:
96         f.write(tomlkit.dumps(toml))
97 
98     try:
99         yield
100     finally:
101         with open(PYPROJECT_TOML, 'w') as f:
102             f.write(original_toml)
103 
104 
105 def patch_dmgbuild():
106     if not MACOS:
107         return
108     from dmgbuild import core
109 
110     # will not be required after dmgbuild > v1.3.3
111     # see https://github.com/al45tair/dmgbuild/pull/18
112     with open(core.__file__) as f:
113         src = f.read()
114     with open(core.__file__, 'w') as f:
115         f.write(
116             src.replace(
117                 "shutil.rmtree(os.path.join(mount_point, '.Trashes'), True)",
118                 "shutil.rmtree(os.path.join(mount_point, '.Trashes'), True);time.sleep(30)",
119             )
120         )
121         print("patched dmgbuild.core")
122 
123 
124 def add_site_packages_to_path():
125     # on mac, make sure the site-packages folder exists even before the user
126     # has pip installed, so it is in sys.path on the first run
127     # (otherwise, newly installed plugins will not be detected until restart)
128     if MACOS:
129         pkgs_dir = os.path.join(
130             APP_DIR,
131             'Contents',
132             'Resources',
133             'Support',
134             'lib',
135             f'python{sys.version_info.major}.{sys.version_info.minor}',
136             'site-packages',
137         )
138         os.makedirs(pkgs_dir)
139         print("created site-packages at", pkgs_dir)
140 
141     # on windows, briefcase uses a _pth file to determine the sys.path at
142     # runtime.  https://docs.python.org/3/using/windows.html#finding-modules
143     # We update that file with the eventual location of pip site-packages
144     elif WINDOWS:
145         py = "".join(map(str, sys.version_info[:2]))
146         python_dir = os.path.join(BUILD_DIR, APP, 'src', 'python')
147         pth = os.path.join(python_dir, f'python{py}._pth')
148         with open(pth, "a") as f:
149             # Append 'hello' at the end of file
150             f.write(".\\\\Lib\\\\site-packages\n")
151         print("added bundled site-packages to", pth)
152 
153         pkgs_dir = os.path.join(python_dir, 'Lib', 'site-packages')
154         os.makedirs(pkgs_dir)
155         print("created site-packages at", pkgs_dir)
156         with open(os.path.join(pkgs_dir, 'readme.txt'), 'w') as f:
157             f.write("this is where plugin packages will go")
158 
159 
160 def patch_wxs():
161     # must run after briefcase create
162     fname = os.path.join(BUILD_DIR, APP, f'{APP}.wxs')
163 
164     if os.path.exists(fname):
165         with open(fname) as f:
166             source = f.read()
167         with open(fname, 'w') as f:
168             f.write(source.replace('pythonw.exe', 'python.exe'))
169             print("patched pythonw.exe -> python.exe")
170 
171 
172 def make_zip():
173     import glob
174     import zipfile
175 
176     if WINDOWS:
177         ext, OS = '*.msi', 'Windows'
178     elif LINUX:
179         ext, OS = '*.AppImage', 'Linux'
180     elif MACOS:
181         ext, OS = '*.dmg', 'macOS'
182     artifact = glob.glob(os.path.join(BUILD_DIR, ext))[0]
183     dest = f'napari-{VERSION}-{OS}.zip'
184 
185     with zipfile.ZipFile(dest, 'w', zipfile.ZIP_DEFLATED) as zf:
186         zf.write(artifact, arcname=os.path.basename(artifact))
187     print("created zipfile: ", dest)
188     return dest
189 
190 
191 def clean():
192     shutil.rmtree(BUILD_DIR, ignore_errors=True)
193 
194 
195 def bundle():
196     clean()
197 
198     if MACOS:
199         patch_dmgbuild()
200 
201     # smoke test, and build resources
202     subprocess.check_call([sys.executable, '-m', APP, '--info'])
203 
204     with patched_toml():
205         # create
206         cmd = ['briefcase', 'create'] + (['--no-docker'] if LINUX else [])
207         subprocess.check_call(cmd)
208 
209         time.sleep(0.5)
210 
211         add_site_packages_to_path()
212 
213         if WINDOWS:
214             patch_wxs()
215 
216     # build
217     cmd = ['briefcase', 'build'] + (['--no-docker'] if LINUX else [])
218     subprocess.check_call(cmd)
219 
220     # package
221     cmd = ['briefcase', 'package']
222     cmd += ['--no-sign'] if MACOS else (['--no-docker'] if LINUX else [])
223     subprocess.check_call(cmd)
224 
225     # compress
226     dest = make_zip()
227     clean()
228 
229     return dest
230 
231 
232 if __name__ == "__main__":
233     if '--clean' in sys.argv:
234         clean()
235         sys.exit()
236     if '--version' in sys.argv:
237         print(VERSION)
238         sys.exit()
239     print('created', bundle())
240
```
--- 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/bundle.py b/bundle.py
--- a/bundle.py
+++ b/bundle.py
@@ -87,9 +87,9 @@
     toml['tool']['briefcase']['app'][APP]['requires'] = requirements
     toml['tool']['briefcase']['version'] = VERSION
 
-    print("patching pyroject.toml to version: ", VERSION)
+    print("patching pyproject.toml to version: ", VERSION)
     print(
-        "patching pyroject.toml requirements to : \n",
+        "patching pyproject.toml requirements to : \n",
         "\n".join(toml['tool']['briefcase']['app'][APP]['requires']),
     )
     with open(PYPROJECT_TOML, 'w') as f:
@@ -107,15 +107,14 @@
         return
     from dmgbuild import core
 
-    # will not be required after dmgbuild > v1.3.3
-    # see https://github.com/al45tair/dmgbuild/pull/18
     with open(core.__file__) as f:
         src = f.read()
     with open(core.__file__, 'w') as f:
         f.write(
             src.replace(
                 "shutil.rmtree(os.path.join(mount_point, '.Trashes'), True)",
-                "shutil.rmtree(os.path.join(mount_point, '.Trashes'), True);time.sleep(30)",
+                "shutil.rmtree(os.path.join(mount_point, '.Trashes'), True)"
+                ";time.sleep(30)",
             )
         )
         print("patched dmgbuild.core")
@@ -201,6 +200,7 @@
     # smoke test, and build resources
     subprocess.check_call([sys.executable, '-m', APP, '--info'])
 
+    # the briefcase calls need to happen while the pyproject toml is patched
     with patched_toml():
         # create
         cmd = ['briefcase', 'create'] + (['--no-docker'] if LINUX else [])
@@ -213,20 +213,20 @@
         if WINDOWS:
             patch_wxs()
 
-    # build
-    cmd = ['briefcase', 'build'] + (['--no-docker'] if LINUX else [])
-    subprocess.check_call(cmd)
+        # build
+        cmd = ['briefcase', 'build'] + (['--no-docker'] if LINUX else [])
+        subprocess.check_call(cmd)
 
-    # package
-    cmd = ['briefcase', 'package']
-    cmd += ['--no-sign'] if MACOS else (['--no-docker'] if LINUX else [])
-    subprocess.check_call(cmd)
+        # package
+        cmd = ['briefcase', 'package']
+        cmd += ['--no-sign'] if MACOS else (['--no-docker'] if LINUX else [])
+        subprocess.check_call(cmd)
 
-    # compress
-    dest = make_zip()
-    clean()
+        # compress
+        dest = make_zip()
+        clean()
 
-    return dest
+        return dest
 
 
 if __name__ == "__main__":

{"golden_diff": "diff --git a/bundle.py b/bundle.py\n--- a/bundle.py\n+++ b/bundle.py\n@@ -87,9 +87,9 @@\n     toml['tool']['briefcase']['app'][APP]['requires'] = requirements\n     toml['tool']['briefcase']['version'] = VERSION\n \n-    print(\"patching pyroject.toml to version: \", VERSION)\n+    print(\"patching pyproject.toml to version: \", VERSION)\n     print(\n-        \"patching pyroject.toml requirements to : \\n\",\n+        \"patching pyproject.toml requirements to : \\n\",\n         \"\\n\".join(toml['tool']['briefcase']['app'][APP]['requires']),\n     )\n     with open(PYPROJECT_TOML, 'w') as f:\n@@ -107,15 +107,14 @@\n         return\n     from dmgbuild import core\n \n-    # will not be required after dmgbuild > v1.3.3\n-    # see https://github.com/al45tair/dmgbuild/pull/18\n     with open(core.__file__) as f:\n         src = f.read()\n     with open(core.__file__, 'w') as f:\n         f.write(\n             src.replace(\n                 \"shutil.rmtree(os.path.join(mount_point, '.Trashes'), True)\",\n-                \"shutil.rmtree(os.path.join(mount_point, '.Trashes'), True);time.sleep(30)\",\n+                \"shutil.rmtree(os.path.join(mount_point, '.Trashes'), True)\"\n+                \";time.sleep(30)\",\n             )\n         )\n         print(\"patched dmgbuild.core\")\n@@ -201,6 +200,7 @@\n     # smoke test, and build resources\n     subprocess.check_call([sys.executable, '-m', APP, '--info'])\n \n+    # the briefcase calls need to happen while the pyproject toml is patched\n     with patched_toml():\n         # create\n         cmd = ['briefcase', 'create'] + (['--no-docker'] if LINUX else [])\n@@ -213,20 +213,20 @@\n         if WINDOWS:\n             patch_wxs()\n \n-    # build\n-    cmd = ['briefcase', 'build'] + (['--no-docker'] if LINUX else [])\n-    subprocess.check_call(cmd)\n+        # build\n+        cmd = ['briefcase', 'build'] + (['--no-docker'] if LINUX else [])\n+        subprocess.check_call(cmd)\n \n-    # package\n-    cmd = ['briefcase', 'package']\n-    cmd += ['--no-sign'] if MACOS else (['--no-docker'] if LINUX else [])\n-    subprocess.check_call(cmd)\n+        # package\n+        cmd = ['briefcase', 'package']\n+        cmd += ['--no-sign'] if MACOS else (['--no-docker'] if LINUX else [])\n+        subprocess.check_call(cmd)\n \n-    # compress\n-    dest = make_zip()\n-    clean()\n+        # compress\n+        dest = make_zip()\n+        clean()\n \n-    return dest\n+        return dest\n \n \n if __name__ == \"__main__\":\n", "issue": "mac thinks that napari is named \"__main__.py\" in bundled app\n## \ud83d\udc1b Bug\r\n\r\nMy mac seems to think that napari is named \"__main__.py\" in bundled app\r\n\r\n## To Reproduce\r\n\r\nSteps to reproduce the behavior:\r\n\r\n1. Launch napari bundled app on mac\r\n2. Click \"napari\" on menu bar\r\n3. See the menu items \"Hide __main__.py\" and \"Close __main__.py\"\r\n\r\n![image](https://user-images.githubusercontent.com/1245615/110528081-f6626e00-80d4-11eb-867b-2b3955d13957.png)\r\n\r\n## Expected behavior\r\n\r\nmenu items include \"Hide napari\" and \"Close napari\", similar to Chrome...\r\n\r\n<!-- A clear and concise description of what you expected to happen. -->\r\n![image](https://user-images.githubusercontent.com/1245615/110528760-bc459c00-80d5-11eb-8ca8-0f04c3247ea1.png)\r\n\r\n## Environment\r\n\r\nnapari: 0.4.6\r\nPlatform: macOS-10.15.7-x86_64-i386-64bit\r\nSystem: MacOS 10.15.7\r\nPython: 3.8.7 (default, Jan 2 2021, 04:16:43) [Clang 11.0.0 (clang-1100.0.33.17)]\r\nQt: 5.15.2\r\nPySide2: 5.15.2\r\nNumPy: 1.19.3\r\nSciPy: 1.6.1\r\nDask: 2021.03.0\r\nVisPy: 0.6.6\r\n\r\nOpenGL:\r\n- GL version: 2.1 ATI-3.10.19\r\n- MAX_TEXTURE_SIZE: 16384\r\n\r\nScreens:\r\n- screen 1: resolution 1792x1120, scale 2.0\r\n- screen 2: resolution 2560x1440, scale 1.0\r\n\r\nPlugins:\r\n- affinder: 0.1.0\r\n- aicsimageio: 0.2.0\r\n- aicsimageio_delayed: 0.2.0\r\n- brainreg: 0.2.3\r\n- brainreg_standard: 0.2.3\r\n- cellfinder: 0.2.1\r\n- console: 0.0.3\r\n- napari-hdf5-labels-io: 0.2.dev1\r\n- ndtiffs: 0.1.1\r\n- svg: 0.1.4\r\n\n", "before_files": [{"content": "import configparser\nimport os\nimport re\nimport shutil\nimport subprocess\nimport sys\nimport time\nfrom contextlib import contextmanager\n\nimport tomlkit\n\nAPP = 'napari'\n\n# EXTRA_REQS will be added to the bundle, in addition to those specified in\n# setup.cfg.  To add additional packages to the bundle, or to override any of\n# the packages listed here or in `setup.cfg, use the `--add` command line\n# argument with a series of \"pip install\" style strings when running this file.\n# For example, the following will ADD ome-zarr, and CHANGE the version of\n# PySide2:\n# python bundle.py --add 'PySide2==5.15.0' 'ome-zarr'\n\nEXTRA_REQS = [\n    \"pip\",\n    \"PySide2==5.15.2\",\n    \"scikit-image\",\n    \"zarr\",\n    \"pims\",\n    \"numpy==1.19.3\",\n]\n\nWINDOWS = os.name == 'nt'\nMACOS = sys.platform == 'darwin'\nLINUX = sys.platform.startswith(\"linux\")\nHERE = os.path.abspath(os.path.dirname(__file__))\nPYPROJECT_TOML = os.path.join(HERE, 'pyproject.toml')\nSETUP_CFG = os.path.join(HERE, 'setup.cfg')\n\nif WINDOWS:\n    BUILD_DIR = os.path.join(HERE, 'windows')\nelif LINUX:\n    BUILD_DIR = os.path.join(HERE, 'linux')\nelif MACOS:\n    BUILD_DIR = os.path.join(HERE, 'macOS')\n    APP_DIR = os.path.join(BUILD_DIR, APP, f'{APP}.app')\n\n\nwith open(os.path.join(HERE, \"napari\", \"_version.py\")) as f:\n    match = re.search(r'version\\s?=\\s?\\'([^\\']+)', f.read())\n    if match:\n        VERSION = match.groups()[0].split('+')[0]\n\n\n@contextmanager\ndef patched_toml():\n    parser = configparser.ConfigParser()\n    parser.read(SETUP_CFG)\n    requirements = parser.get(\"options\", \"install_requires\").splitlines()\n    requirements = [r.split('#')[0].strip() for r in requirements if r]\n\n    with open(PYPROJECT_TOML) as f:\n        original_toml = f.read()\n\n    toml = tomlkit.parse(original_toml)\n\n    # parse command line arguments\n    if '--add' in sys.argv:\n        for item in sys.argv[sys.argv.index('--add') + 1 :]:\n            if item.startswith('-'):\n                break\n            EXTRA_REQS.append(item)\n\n    for item in EXTRA_REQS:\n        _base = re.split('<|>|=', item, maxsplit=1)[0]\n        for r in requirements:\n            if r.startswith(_base):\n                requirements.remove(r)\n                break\n        if _base.lower().startswith('pyqt5'):\n            try:\n                i = next(x for x in requirements if x.startswith('PySide'))\n                requirements.remove(i)\n            except StopIteration:\n                pass\n\n    requirements += EXTRA_REQS\n\n    toml['tool']['briefcase']['app'][APP]['requires'] = requirements\n    toml['tool']['briefcase']['version'] = VERSION\n\n    print(\"patching pyroject.toml to version: \", VERSION)\n    print(\n        \"patching pyroject.toml requirements to : \\n\",\n        \"\\n\".join(toml['tool']['briefcase']['app'][APP]['requires']),\n    )\n    with open(PYPROJECT_TOML, 'w') as f:\n        f.write(tomlkit.dumps(toml))\n\n    try:\n        yield\n    finally:\n        with open(PYPROJECT_TOML, 'w') as f:\n            f.write(original_toml)\n\n\ndef patch_dmgbuild():\n    if not MACOS:\n        return\n    from dmgbuild import core\n\n    # will not be required after dmgbuild > v1.3.3\n    # see https://github.com/al45tair/dmgbuild/pull/18\n    with open(core.__file__) as f:\n        src = f.read()\n    with open(core.__file__, 'w') as f:\n        f.write(\n            src.replace(\n                \"shutil.rmtree(os.path.join(mount_point, '.Trashes'), True)\",\n                \"shutil.rmtree(os.path.join(mount_point, '.Trashes'), True);time.sleep(30)\",\n            )\n        )\n        print(\"patched dmgbuild.core\")\n\n\ndef add_site_packages_to_path():\n    # on mac, make sure the site-packages folder exists even before the user\n    # has pip installed, so it is in sys.path on the first run\n    # (otherwise, newly installed plugins will not be detected until restart)\n    if MACOS:\n        pkgs_dir = os.path.join(\n            APP_DIR,\n            'Contents',\n            'Resources',\n            'Support',\n            'lib',\n            f'python{sys.version_info.major}.{sys.version_info.minor}',\n            'site-packages',\n        )\n        os.makedirs(pkgs_dir)\n        print(\"created site-packages at\", pkgs_dir)\n\n    # on windows, briefcase uses a _pth file to determine the sys.path at\n    # runtime.  https://docs.python.org/3/using/windows.html#finding-modules\n    # We update that file with the eventual location of pip site-packages\n    elif WINDOWS:\n        py = \"\".join(map(str, sys.version_info[:2]))\n        python_dir = os.path.join(BUILD_DIR, APP, 'src', 'python')\n        pth = os.path.join(python_dir, f'python{py}._pth')\n        with open(pth, \"a\") as f:\n            # Append 'hello' at the end of file\n            f.write(\".\\\\\\\\Lib\\\\\\\\site-packages\\n\")\n        print(\"added bundled site-packages to\", pth)\n\n        pkgs_dir = os.path.join(python_dir, 'Lib', 'site-packages')\n        os.makedirs(pkgs_dir)\n        print(\"created site-packages at\", pkgs_dir)\n        with open(os.path.join(pkgs_dir, 'readme.txt'), 'w') as f:\n            f.write(\"this is where plugin packages will go\")\n\n\ndef patch_wxs():\n    # must run after briefcase create\n    fname = os.path.join(BUILD_DIR, APP, f'{APP}.wxs')\n\n    if os.path.exists(fname):\n        with open(fname) as f:\n            source = f.read()\n        with open(fname, 'w') as f:\n            f.write(source.replace('pythonw.exe', 'python.exe'))\n            print(\"patched pythonw.exe -> python.exe\")\n\n\ndef make_zip():\n    import glob\n    import zipfile\n\n    if WINDOWS:\n        ext, OS = '*.msi', 'Windows'\n    elif LINUX:\n        ext, OS = '*.AppImage', 'Linux'\n    elif MACOS:\n        ext, OS = '*.dmg', 'macOS'\n    artifact = glob.glob(os.path.join(BUILD_DIR, ext))[0]\n    dest = f'napari-{VERSION}-{OS}.zip'\n\n    with zipfile.ZipFile(dest, 'w', zipfile.ZIP_DEFLATED) as zf:\n        zf.write(artifact, arcname=os.path.basename(artifact))\n    print(\"created zipfile: \", dest)\n    return dest\n\n\ndef clean():\n    shutil.rmtree(BUILD_DIR, ignore_errors=True)\n\n\ndef bundle():\n    clean()\n\n    if MACOS:\n        patch_dmgbuild()\n\n    # smoke test, and build resources\n    subprocess.check_call([sys.executable, '-m', APP, '--info'])\n\n    with patched_toml():\n        # create\n        cmd = ['briefcase', 'create'] + (['--no-docker'] if LINUX else [])\n        subprocess.check_call(cmd)\n\n        time.sleep(0.5)\n\n        add_site_packages_to_path()\n\n        if WINDOWS:\n            patch_wxs()\n\n    # build\n    cmd = ['briefcase', 'build'] + (['--no-docker'] if LINUX else [])\n    subprocess.check_call(cmd)\n\n    # package\n    cmd = ['briefcase', 'package']\n    cmd += ['--no-sign'] if MACOS else (['--no-docker'] if LINUX else [])\n    subprocess.check_call(cmd)\n\n    # compress\n    dest = make_zip()\n    clean()\n\n    return dest\n\n\nif __name__ == \"__main__\":\n    if '--clean' in sys.argv:\n        clean()\n        sys.exit()\n    if '--version' in sys.argv:\n        print(VERSION)\n        sys.exit()\n    print('created', bundle())\n", "path": "bundle.py"}], "after_files": [{"content": "import configparser\nimport os\nimport re\nimport shutil\nimport subprocess\nimport sys\nimport time\nfrom contextlib import contextmanager\n\nimport tomlkit\n\nAPP = 'napari'\n\n# EXTRA_REQS will be added to the bundle, in addition to those specified in\n# setup.cfg.  To add additional packages to the bundle, or to override any of\n# the packages listed here or in `setup.cfg, use the `--add` command line\n# argument with a series of \"pip install\" style strings when running this file.\n# For example, the following will ADD ome-zarr, and CHANGE the version of\n# PySide2:\n# python bundle.py --add 'PySide2==5.15.0' 'ome-zarr'\n\nEXTRA_REQS = [\n    \"pip\",\n    \"PySide2==5.15.2\",\n    \"scikit-image\",\n    \"zarr\",\n    \"pims\",\n    \"numpy==1.19.3\",\n]\n\nWINDOWS = os.name == 'nt'\nMACOS = sys.platform == 'darwin'\nLINUX = sys.platform.startswith(\"linux\")\nHERE = os.path.abspath(os.path.dirname(__file__))\nPYPROJECT_TOML = os.path.join(HERE, 'pyproject.toml')\nSETUP_CFG = os.path.join(HERE, 'setup.cfg')\n\nif WINDOWS:\n    BUILD_DIR = os.path.join(HERE, 'windows')\nelif LINUX:\n    BUILD_DIR = os.path.join(HERE, 'linux')\nelif MACOS:\n    BUILD_DIR = os.path.join(HERE, 'macOS')\n    APP_DIR = os.path.join(BUILD_DIR, APP, f'{APP}.app')\n\n\nwith open(os.path.join(HERE, \"napari\", \"_version.py\")) as f:\n    match = re.search(r'version\\s?=\\s?\\'([^\\']+)', f.read())\n    if match:\n        VERSION = match.groups()[0].split('+')[0]\n\n\n@contextmanager\ndef patched_toml():\n    parser = configparser.ConfigParser()\n    parser.read(SETUP_CFG)\n    requirements = parser.get(\"options\", \"install_requires\").splitlines()\n    requirements = [r.split('#')[0].strip() for r in requirements if r]\n\n    with open(PYPROJECT_TOML) as f:\n        original_toml = f.read()\n\n    toml = tomlkit.parse(original_toml)\n\n    # parse command line arguments\n    if '--add' in sys.argv:\n        for item in sys.argv[sys.argv.index('--add') + 1 :]:\n            if item.startswith('-'):\n                break\n            EXTRA_REQS.append(item)\n\n    for item in EXTRA_REQS:\n        _base = re.split('<|>|=', item, maxsplit=1)[0]\n        for r in requirements:\n            if r.startswith(_base):\n                requirements.remove(r)\n                break\n        if _base.lower().startswith('pyqt5'):\n            try:\n                i = next(x for x in requirements if x.startswith('PySide'))\n                requirements.remove(i)\n            except StopIteration:\n                pass\n\n    requirements += EXTRA_REQS\n\n    toml['tool']['briefcase']['app'][APP]['requires'] = requirements\n    toml['tool']['briefcase']['version'] = VERSION\n\n    print(\"patching pyproject.toml to version: \", VERSION)\n    print(\n        \"patching pyproject.toml requirements to : \\n\",\n        \"\\n\".join(toml['tool']['briefcase']['app'][APP]['requires']),\n    )\n    with open(PYPROJECT_TOML, 'w') as f:\n        f.write(tomlkit.dumps(toml))\n\n    try:\n        yield\n    finally:\n        with open(PYPROJECT_TOML, 'w') as f:\n            f.write(original_toml)\n\n\ndef patch_dmgbuild():\n    if not MACOS:\n        return\n    from dmgbuild import core\n\n    with open(core.__file__) as f:\n        src = f.read()\n    with open(core.__file__, 'w') as f:\n        f.write(\n            src.replace(\n                \"shutil.rmtree(os.path.join(mount_point, '.Trashes'), True)\",\n                \"shutil.rmtree(os.path.join(mount_point, '.Trashes'), True)\"\n                \";time.sleep(30)\",\n            )\n        )\n        print(\"patched dmgbuild.core\")\n\n\ndef add_site_packages_to_path():\n    # on mac, make sure the site-packages folder exists even before the user\n    # has pip installed, so it is in sys.path on the first run\n    # (otherwise, newly installed plugins will not be detected until restart)\n    if MACOS:\n        pkgs_dir = os.path.join(\n            APP_DIR,\n            'Contents',\n            'Resources',\n            'Support',\n            'lib',\n            f'python{sys.version_info.major}.{sys.version_info.minor}',\n            'site-packages',\n        )\n        os.makedirs(pkgs_dir)\n        print(\"created site-packages at\", pkgs_dir)\n\n    # on windows, briefcase uses a _pth file to determine the sys.path at\n    # runtime.  https://docs.python.org/3/using/windows.html#finding-modules\n    # We update that file with the eventual location of pip site-packages\n    elif WINDOWS:\n        py = \"\".join(map(str, sys.version_info[:2]))\n        python_dir = os.path.join(BUILD_DIR, APP, 'src', 'python')\n        pth = os.path.join(python_dir, f'python{py}._pth')\n        with open(pth, \"a\") as f:\n            # Append 'hello' at the end of file\n            f.write(\".\\\\\\\\Lib\\\\\\\\site-packages\\n\")\n        print(\"added bundled site-packages to\", pth)\n\n        pkgs_dir = os.path.join(python_dir, 'Lib', 'site-packages')\n        os.makedirs(pkgs_dir)\n        print(\"created site-packages at\", pkgs_dir)\n        with open(os.path.join(pkgs_dir, 'readme.txt'), 'w') as f:\n            f.write(\"this is where plugin packages will go\")\n\n\ndef patch_wxs():\n    # must run after briefcase create\n    fname = os.path.join(BUILD_DIR, APP, f'{APP}.wxs')\n\n    if os.path.exists(fname):\n        with open(fname) as f:\n            source = f.read()\n        with open(fname, 'w') as f:\n            f.write(source.replace('pythonw.exe', 'python.exe'))\n            print(\"patched pythonw.exe -> python.exe\")\n\n\ndef make_zip():\n    import glob\n    import zipfile\n\n    if WINDOWS:\n        ext, OS = '*.msi', 'Windows'\n    elif LINUX:\n        ext, OS = '*.AppImage', 'Linux'\n    elif MACOS:\n        ext, OS = '*.dmg', 'macOS'\n    artifact = glob.glob(os.path.join(BUILD_DIR, ext))[0]\n    dest = f'napari-{VERSION}-{OS}.zip'\n\n    with zipfile.ZipFile(dest, 'w', zipfile.ZIP_DEFLATED) as zf:\n        zf.write(artifact, arcname=os.path.basename(artifact))\n    print(\"created zipfile: \", dest)\n    return dest\n\n\ndef clean():\n    shutil.rmtree(BUILD_DIR, ignore_errors=True)\n\n\ndef bundle():\n    clean()\n\n    if MACOS:\n        patch_dmgbuild()\n\n    # smoke test, and build resources\n    subprocess.check_call([sys.executable, '-m', APP, '--info'])\n\n    # the briefcase calls need to happen while the pyproject toml is patched\n    with patched_toml():\n        # create\n        cmd = ['briefcase', 'create'] + (['--no-docker'] if LINUX else [])\n        subprocess.check_call(cmd)\n\n        time.sleep(0.5)\n\n        add_site_packages_to_path()\n\n        if WINDOWS:\n            patch_wxs()\n\n        # build\n        cmd = ['briefcase', 'build'] + (['--no-docker'] if LINUX else [])\n        subprocess.check_call(cmd)\n\n        # package\n        cmd = ['briefcase', 'package']\n        cmd += ['--no-sign'] if MACOS else (['--no-docker'] if LINUX else [])\n        subprocess.check_call(cmd)\n\n        # compress\n        dest = make_zip()\n        clean()\n\n        return dest\n\n\nif __name__ == \"__main__\":\n    if '--clean' in sys.argv:\n        clean()\n        sys.exit()\n    if '--version' in sys.argv:\n        print(VERSION)\n        sys.exit()\n    print('created', bundle())\n", "path": "bundle.py"}]}