We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
tarball from PyPI requires git
**Describe the bug**
Source tarball taken from PyPI https://pypi.org/project/qutip/ fails without git:
```
===>  Configuring for py38-qutip-4.6.0
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "setup.py", line 231, in <module>
    options = process_options()
  File "setup.py", line 45, in process_options
    options = _determine_version(options)
  File "setup.py", line 127, in _determine_version
    git_out = subprocess.run(
  File "/usr/local/lib/python3.8/subprocess.py", line 493, in run
    with Popen(*popenargs, **kwargs) as process:
  File "/usr/local/lib/python3.8/subprocess.py", line 858, in __init__
    self._execute_child(args, executable, preexec_fn, close_fds,
  File "/usr/local/lib/python3.8/subprocess.py", line 1704, in _execute_child
    raise child_exception_type(errno_num, err_msg, err_filename)
FileNotFoundError: [Errno 2] No such file or directory: 'git'
```

git shouldn't be required because PyPI != GitHub and it is expected to be just a directory and not a cloned git repository.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `setup.py`
Content:
```
1 #!/usr/bin/env python
2 
3 import collections
4 import os
5 import pathlib
6 import re
7 import subprocess
8 import sys
9 import sysconfig
10 import warnings
11 
12 # Required third-party imports, must be specified in pyproject.toml.
13 from setuptools import setup, Extension
14 import distutils.sysconfig
15 import numpy as np
16 from Cython.Build import cythonize
17 from Cython.Distutils import build_ext
18 
19 
20 def process_options():
21     """
22     Determine all runtime options, returning a dictionary of the results.  The
23     keys are:
24         'rootdir': str
25             The root directory of the setup.  Almost certainly the directory
26             that this setup.py file is contained in.
27         'release': bool
28             Is this a release build (True) or a local development build (False)
29         'openmp': bool
30             Should we build our OpenMP extensions and attempt to link in OpenMP
31             libraries?
32         'cflags': list of str
33             Flags to be passed to the C++ compiler.
34         'ldflags': list of str
35             Flags to be passed to the linker.
36         'include': list of str
37             Additional directories to be added to the header files include
38             path.  These files will be detected by Cython as dependencies, so
39             changes to them will trigger recompilation of .pyx files, whereas
40             includes added in 'cflags' as '-I/path/to/include' may not.
41     """
42     options = {}
43     options['rootdir'] = os.path.dirname(os.path.abspath(__file__))
44     options = _determine_user_arguments(options)
45     options = _determine_version(options)
46     options = _determine_compilation_options(options)
47     return options
48 
49 
50 def _determine_user_arguments(options):
51     """
52     Add the 'release' and 'openmp' options to the collection, based on the
53     passed command-line arguments or environment variables.
54     """
55     options['release'] = (
56         '--release' in sys.argv
57         or bool(os.environ.get('CI_QUTIP_RELEASE'))
58     )
59     if '--release' in sys.argv:
60         sys.argv.remove('--release')
61     options['openmp'] = (
62         '--with-openmp' in sys.argv
63         or bool(os.environ.get('CI_QUTIP_WITH_OPENMP'))
64     )
65     if "--with-openmp" in sys.argv:
66         sys.argv.remove("--with-openmp")
67     return options
68 
69 
70 def _determine_compilation_options(options):
71     """
72     Add additional options specific to C/C++ compilation.  These are 'cflags',
73     'ldflags' and 'include'.
74     """
75     # Remove -Wstrict-prototypes from the CFLAGS variable that the Python build
76     # process uses in addition to user-specified ones; the flag is not valid
77     # for C++ compiles, but CFLAGS gets appended to those compiles anyway.
78     config = distutils.sysconfig.get_config_vars()
79     if "CFLAGS" in config:
80         config["CFLAGS"] = config["CFLAGS"].replace("-Wstrict-prototypes", "")
81     options['cflags'] = []
82     options['ldflags'] = []
83     options['include'] = [np.get_include()]
84     if (
85         sysconfig.get_platform().startswith("win")
86         and os.environ.get('MSYSTEM') is None
87     ):
88         # Visual Studio
89         options['cflags'].extend(['/w', '/Ox'])
90         if options['openmp']:
91             options['cflags'].append('/openmp')
92     else:
93         # Everything else
94         options['cflags'].extend(['-w', '-O3', '-funroll-loops'])
95     if sysconfig.get_platform().startswith("macos"):
96         # These are needed for compiling on OSX 10.14+
97         options['cflags'].append('-mmacosx-version-min=10.9')
98         options['ldflags'].append('-mmacosx-version-min=10.9')
99         if options['openmp']:
100             options['cflags'].append('-fopenmp')
101             options['ldflags'].append('-fopenmp')
102     return options
103 
104 
105 def _determine_version(options):
106     """
107     Adds the 'short_version' and 'version' options.
108 
109     Read from the VERSION file to discover the version.  This should be a
110     single line file containing valid Python package public identifier (see PEP
111     440), for example
112       4.5.2rc2
113       5.0.0
114       5.1.1a1
115     We do that here rather than in setup.cfg so we can apply the local
116     versioning number as well.
117     """
118     version_filename = os.path.join(options['rootdir'], 'VERSION')
119     with open(version_filename, "r") as version_file:
120         version = options['short_version'] = version_file.read().strip()
121     VERSION_RE = r'\d+(\.\d+)*((a|b|rc)\d+)?(\.post\d+)?(\.dev\d+)?'
122     if re.fullmatch(VERSION_RE, version, re.A) is None:
123         raise ValueError("invalid version: " + version)
124     if not options['release']:
125         version += "+"
126         try:
127             git_out = subprocess.run(
128                 ('git', 'rev-parse', '--verify', '--short=7', 'HEAD'),
129                 check=True,
130                 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
131             )
132             git_hash = git_out.stdout.decode(sys.stdout.encoding).strip()
133             version += git_hash or "nogit"
134         except subprocess.CalledProcessError:
135             version += "nogit"
136     options['version'] = version
137     return options
138 
139 
140 def create_version_py_file(options):
141     """
142     Generate and write out the file qutip/version.py, which is used to produce
143     the '__version__' information for the module.  This function will overwrite
144     an existing file at that location.
145     """
146     filename = os.path.join(options['rootdir'], 'qutip', 'version.py')
147     content = "\n".join([
148         f"# This file is automatically generated by QuTiP's setup.py.",
149         f"short_version = '{options['short_version']}'",
150         f"version = '{options['version']}'",
151         f"release = {options['release']}",
152     ])
153     with open(filename, 'w') as file:
154         print(content, file=file)
155 
156 
157 def _extension_extra_sources():
158     """
159     Get a mapping of {module: extra_sources} for all modules to be built.  The
160     module is the fully qualified Python module (e.g. 'qutip.cy.spmatfuncs'),
161     and extra_sources is a list of strings of relative paths to files.  If no
162     extra sources are known for a given module, the mapping will return an
163     empty list.
164     """
165     # For typing brevity we specify sources in Unix-style string form, then
166     # normalise them into the OS-specific form later.
167     extra_sources = {
168         'qutip.cy.spmatfuncs': ['qutip/cy/src/zspmv.cpp'],
169         'qutip.cy.openmp.parfuncs': ['qutip/cy/openmp/src/zspmv_openmp.cpp'],
170     }
171     out = collections.defaultdict(list)
172     for module, sources in extra_sources.items():
173         # Normalise the sources into OS-specific form.
174         out[module] = [str(pathlib.Path(source)) for source in sources]
175     return out
176 
177 
178 def create_extension_modules(options):
179     """
180     Discover and Cythonise all extension modules that need to be built.  These
181     are returned so they can be passed into the setup command.
182     """
183     out = []
184     root = pathlib.Path(options['rootdir'])
185     pyx_files = set(root.glob('qutip/**/*.pyx'))
186     if not options['openmp']:
187         pyx_files -= set(root.glob('qutip/**/openmp/**/*.pyx'))
188     extra_sources = _extension_extra_sources()
189     # Add Cython files from qutip
190     for pyx_file in pyx_files:
191         pyx_file = pyx_file.relative_to(root)
192         pyx_file_str = str(pyx_file)
193         if 'compiled_coeff' in pyx_file_str or 'qtcoeff_' in pyx_file_str:
194             # In development (at least for QuTiP ~4.5 and ~5.0) sometimes the
195             # Cythonised time-dependent coefficients would get dropped in the
196             # qutip directory if you weren't careful - this is just trying to
197             # minimise the occasional developer error.
198             warnings.warn(
199                 "skipping generated time-dependent coefficient: "
200                 + pyx_file_str
201             )
202             continue
203         # The module name is the same as the folder structure, but with dots in
204         # place of separators ('/' or '\'), and without the '.pyx' extension.
205         pyx_module = ".".join(pyx_file.parts)[:-4]
206         pyx_sources = [pyx_file_str] + extra_sources[pyx_module]
207         out.append(Extension(pyx_module,
208                              sources=pyx_sources,
209                              include_dirs=options['include'],
210                              extra_compile_args=options['cflags'],
211                              extra_link_args=options['ldflags'],
212                              language='c++'))
213     return cythonize(out)
214 
215 
216 def print_epilogue():
217     """Display a post-setup epilogue."""
218     longbar = "="*80
219     message = "\n".join([
220         longbar,
221         "Installation complete",
222         "Please cite QuTiP in your publication.",
223         longbar,
224         "For your convenience a BibTeX reference can be easily generated with",
225         "`qutip.cite()`",
226     ])
227     print(message)
228 
229 
230 if __name__ == "__main__":
231     options = process_options()
232     create_version_py_file(options)
233     extensions = create_extension_modules(options)
234     # Most of the kwargs to setup are defined in setup.cfg; the only ones we
235     # keep here are ones that we have done some compile-time processing on.
236     setup(
237         version=options['version'],
238         ext_modules=extensions,
239         cmdclass={'build_ext': build_ext},
240     )
241     print_epilogue()
242
```
--- 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/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -10,6 +10,7 @@
 import warnings
 
 # Required third-party imports, must be specified in pyproject.toml.
+import packaging.version
 from setuptools import setup, Extension
 import distutils.sysconfig
 import numpy as np
@@ -49,15 +50,9 @@
 
 def _determine_user_arguments(options):
     """
-    Add the 'release' and 'openmp' options to the collection, based on the
-    passed command-line arguments or environment variables.
+    Add the 'openmp' option to the collection, based on the passed command-line
+    arguments or environment variables.
     """
-    options['release'] = (
-        '--release' in sys.argv
-        or bool(os.environ.get('CI_QUTIP_RELEASE'))
-    )
-    if '--release' in sys.argv:
-        sys.argv.remove('--release')
     options['openmp'] = (
         '--with-openmp' in sys.argv
         or bool(os.environ.get('CI_QUTIP_WITH_OPENMP'))
@@ -104,7 +99,7 @@
 
 def _determine_version(options):
     """
-    Adds the 'short_version' and 'version' options.
+    Adds the 'short_version', 'version' and 'release' options.
 
     Read from the VERSION file to discover the version.  This should be a
     single line file containing valid Python package public identifier (see PEP
@@ -117,12 +112,16 @@
     """
     version_filename = os.path.join(options['rootdir'], 'VERSION')
     with open(version_filename, "r") as version_file:
-        version = options['short_version'] = version_file.read().strip()
-    VERSION_RE = r'\d+(\.\d+)*((a|b|rc)\d+)?(\.post\d+)?(\.dev\d+)?'
-    if re.fullmatch(VERSION_RE, version, re.A) is None:
-        raise ValueError("invalid version: " + version)
+        version_string = version_file.read().strip()
+    version = packaging.version.parse(version_string)
+    if isinstance(version, packaging.version.LegacyVersion):
+        raise ValueError("invalid version: " + version_string)
+    options['short_version'] = str(version.public)
+    options['release'] = not version.is_devrelease
     if not options['release']:
-        version += "+"
+        # Put the version string into canonical form, if it wasn't already.
+        version_string = str(version)
+        version_string += "+"
         try:
             git_out = subprocess.run(
                 ('git', 'rev-parse', '--verify', '--short=7', 'HEAD'),
@@ -130,10 +129,14 @@
                 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
             )
             git_hash = git_out.stdout.decode(sys.stdout.encoding).strip()
-            version += git_hash or "nogit"
-        except subprocess.CalledProcessError:
-            version += "nogit"
-    options['version'] = version
+            version_string += git_hash or "nogit"
+        # CalledProcessError is for if the git command fails for internal
+        # reasons (e.g. we're not in a git repository), OSError is for if
+        # something goes wrong when trying to run git (e.g. it's not installed,
+        # or a permission error).
+        except (subprocess.CalledProcessError, OSError):
+            version_string += "nogit"
+    options['version'] = version_string
     return options

{"golden_diff": "diff --git a/setup.py b/setup.py\n--- a/setup.py\n+++ b/setup.py\n@@ -10,6 +10,7 @@\n import warnings\n \n # Required third-party imports, must be specified in pyproject.toml.\n+import packaging.version\n from setuptools import setup, Extension\n import distutils.sysconfig\n import numpy as np\n@@ -49,15 +50,9 @@\n \n def _determine_user_arguments(options):\n     \"\"\"\n-    Add the 'release' and 'openmp' options to the collection, based on the\n-    passed command-line arguments or environment variables.\n+    Add the 'openmp' option to the collection, based on the passed command-line\n+    arguments or environment variables.\n     \"\"\"\n-    options['release'] = (\n-        '--release' in sys.argv\n-        or bool(os.environ.get('CI_QUTIP_RELEASE'))\n-    )\n-    if '--release' in sys.argv:\n-        sys.argv.remove('--release')\n     options['openmp'] = (\n         '--with-openmp' in sys.argv\n         or bool(os.environ.get('CI_QUTIP_WITH_OPENMP'))\n@@ -104,7 +99,7 @@\n \n def _determine_version(options):\n     \"\"\"\n-    Adds the 'short_version' and 'version' options.\n+    Adds the 'short_version', 'version' and 'release' options.\n \n     Read from the VERSION file to discover the version.  This should be a\n     single line file containing valid Python package public identifier (see PEP\n@@ -117,12 +112,16 @@\n     \"\"\"\n     version_filename = os.path.join(options['rootdir'], 'VERSION')\n     with open(version_filename, \"r\") as version_file:\n-        version = options['short_version'] = version_file.read().strip()\n-    VERSION_RE = r'\\d+(\\.\\d+)*((a|b|rc)\\d+)?(\\.post\\d+)?(\\.dev\\d+)?'\n-    if re.fullmatch(VERSION_RE, version, re.A) is None:\n-        raise ValueError(\"invalid version: \" + version)\n+        version_string = version_file.read().strip()\n+    version = packaging.version.parse(version_string)\n+    if isinstance(version, packaging.version.LegacyVersion):\n+        raise ValueError(\"invalid version: \" + version_string)\n+    options['short_version'] = str(version.public)\n+    options['release'] = not version.is_devrelease\n     if not options['release']:\n-        version += \"+\"\n+        # Put the version string into canonical form, if it wasn't already.\n+        version_string = str(version)\n+        version_string += \"+\"\n         try:\n             git_out = subprocess.run(\n                 ('git', 'rev-parse', '--verify', '--short=7', 'HEAD'),\n@@ -130,10 +129,14 @@\n                 stdout=subprocess.PIPE, stderr=subprocess.PIPE,\n             )\n             git_hash = git_out.stdout.decode(sys.stdout.encoding).strip()\n-            version += git_hash or \"nogit\"\n-        except subprocess.CalledProcessError:\n-            version += \"nogit\"\n-    options['version'] = version\n+            version_string += git_hash or \"nogit\"\n+        # CalledProcessError is for if the git command fails for internal\n+        # reasons (e.g. we're not in a git repository), OSError is for if\n+        # something goes wrong when trying to run git (e.g. it's not installed,\n+        # or a permission error).\n+        except (subprocess.CalledProcessError, OSError):\n+            version_string += \"nogit\"\n+    options['version'] = version_string\n     return options\n", "issue": "tarball from PyPI requires git\n**Describe the bug**\r\nSource tarball taken from PyPI https://pypi.org/project/qutip/ fails without git:\r\n```\r\n===>  Configuring for py38-qutip-4.6.0\r\nTraceback (most recent call last):\r\n  File \"<string>\", line 1, in <module>\r\n  File \"setup.py\", line 231, in <module>\r\n    options = process_options()\r\n  File \"setup.py\", line 45, in process_options\r\n    options = _determine_version(options)\r\n  File \"setup.py\", line 127, in _determine_version\r\n    git_out = subprocess.run(\r\n  File \"/usr/local/lib/python3.8/subprocess.py\", line 493, in run\r\n    with Popen(*popenargs, **kwargs) as process:\r\n  File \"/usr/local/lib/python3.8/subprocess.py\", line 858, in __init__\r\n    self._execute_child(args, executable, preexec_fn, close_fds,\r\n  File \"/usr/local/lib/python3.8/subprocess.py\", line 1704, in _execute_child\r\n    raise child_exception_type(errno_num, err_msg, err_filename)\r\nFileNotFoundError: [Errno 2] No such file or directory: 'git'\r\n```\r\n\r\ngit shouldn't be required because PyPI != GitHub and it is expected to be just a directory and not a cloned git repository.\r\n\n", "before_files": [{"content": "#!/usr/bin/env python\n\nimport collections\nimport os\nimport pathlib\nimport re\nimport subprocess\nimport sys\nimport sysconfig\nimport warnings\n\n# Required third-party imports, must be specified in pyproject.toml.\nfrom setuptools import setup, Extension\nimport distutils.sysconfig\nimport numpy as np\nfrom Cython.Build import cythonize\nfrom Cython.Distutils import build_ext\n\n\ndef process_options():\n    \"\"\"\n    Determine all runtime options, returning a dictionary of the results.  The\n    keys are:\n        'rootdir': str\n            The root directory of the setup.  Almost certainly the directory\n            that this setup.py file is contained in.\n        'release': bool\n            Is this a release build (True) or a local development build (False)\n        'openmp': bool\n            Should we build our OpenMP extensions and attempt to link in OpenMP\n            libraries?\n        'cflags': list of str\n            Flags to be passed to the C++ compiler.\n        'ldflags': list of str\n            Flags to be passed to the linker.\n        'include': list of str\n            Additional directories to be added to the header files include\n            path.  These files will be detected by Cython as dependencies, so\n            changes to them will trigger recompilation of .pyx files, whereas\n            includes added in 'cflags' as '-I/path/to/include' may not.\n    \"\"\"\n    options = {}\n    options['rootdir'] = os.path.dirname(os.path.abspath(__file__))\n    options = _determine_user_arguments(options)\n    options = _determine_version(options)\n    options = _determine_compilation_options(options)\n    return options\n\n\ndef _determine_user_arguments(options):\n    \"\"\"\n    Add the 'release' and 'openmp' options to the collection, based on the\n    passed command-line arguments or environment variables.\n    \"\"\"\n    options['release'] = (\n        '--release' in sys.argv\n        or bool(os.environ.get('CI_QUTIP_RELEASE'))\n    )\n    if '--release' in sys.argv:\n        sys.argv.remove('--release')\n    options['openmp'] = (\n        '--with-openmp' in sys.argv\n        or bool(os.environ.get('CI_QUTIP_WITH_OPENMP'))\n    )\n    if \"--with-openmp\" in sys.argv:\n        sys.argv.remove(\"--with-openmp\")\n    return options\n\n\ndef _determine_compilation_options(options):\n    \"\"\"\n    Add additional options specific to C/C++ compilation.  These are 'cflags',\n    'ldflags' and 'include'.\n    \"\"\"\n    # Remove -Wstrict-prototypes from the CFLAGS variable that the Python build\n    # process uses in addition to user-specified ones; the flag is not valid\n    # for C++ compiles, but CFLAGS gets appended to those compiles anyway.\n    config = distutils.sysconfig.get_config_vars()\n    if \"CFLAGS\" in config:\n        config[\"CFLAGS\"] = config[\"CFLAGS\"].replace(\"-Wstrict-prototypes\", \"\")\n    options['cflags'] = []\n    options['ldflags'] = []\n    options['include'] = [np.get_include()]\n    if (\n        sysconfig.get_platform().startswith(\"win\")\n        and os.environ.get('MSYSTEM') is None\n    ):\n        # Visual Studio\n        options['cflags'].extend(['/w', '/Ox'])\n        if options['openmp']:\n            options['cflags'].append('/openmp')\n    else:\n        # Everything else\n        options['cflags'].extend(['-w', '-O3', '-funroll-loops'])\n    if sysconfig.get_platform().startswith(\"macos\"):\n        # These are needed for compiling on OSX 10.14+\n        options['cflags'].append('-mmacosx-version-min=10.9')\n        options['ldflags'].append('-mmacosx-version-min=10.9')\n        if options['openmp']:\n            options['cflags'].append('-fopenmp')\n            options['ldflags'].append('-fopenmp')\n    return options\n\n\ndef _determine_version(options):\n    \"\"\"\n    Adds the 'short_version' and 'version' options.\n\n    Read from the VERSION file to discover the version.  This should be a\n    single line file containing valid Python package public identifier (see PEP\n    440), for example\n      4.5.2rc2\n      5.0.0\n      5.1.1a1\n    We do that here rather than in setup.cfg so we can apply the local\n    versioning number as well.\n    \"\"\"\n    version_filename = os.path.join(options['rootdir'], 'VERSION')\n    with open(version_filename, \"r\") as version_file:\n        version = options['short_version'] = version_file.read().strip()\n    VERSION_RE = r'\\d+(\\.\\d+)*((a|b|rc)\\d+)?(\\.post\\d+)?(\\.dev\\d+)?'\n    if re.fullmatch(VERSION_RE, version, re.A) is None:\n        raise ValueError(\"invalid version: \" + version)\n    if not options['release']:\n        version += \"+\"\n        try:\n            git_out = subprocess.run(\n                ('git', 'rev-parse', '--verify', '--short=7', 'HEAD'),\n                check=True,\n                stdout=subprocess.PIPE, stderr=subprocess.PIPE,\n            )\n            git_hash = git_out.stdout.decode(sys.stdout.encoding).strip()\n            version += git_hash or \"nogit\"\n        except subprocess.CalledProcessError:\n            version += \"nogit\"\n    options['version'] = version\n    return options\n\n\ndef create_version_py_file(options):\n    \"\"\"\n    Generate and write out the file qutip/version.py, which is used to produce\n    the '__version__' information for the module.  This function will overwrite\n    an existing file at that location.\n    \"\"\"\n    filename = os.path.join(options['rootdir'], 'qutip', 'version.py')\n    content = \"\\n\".join([\n        f\"# This file is automatically generated by QuTiP's setup.py.\",\n        f\"short_version = '{options['short_version']}'\",\n        f\"version = '{options['version']}'\",\n        f\"release = {options['release']}\",\n    ])\n    with open(filename, 'w') as file:\n        print(content, file=file)\n\n\ndef _extension_extra_sources():\n    \"\"\"\n    Get a mapping of {module: extra_sources} for all modules to be built.  The\n    module is the fully qualified Python module (e.g. 'qutip.cy.spmatfuncs'),\n    and extra_sources is a list of strings of relative paths to files.  If no\n    extra sources are known for a given module, the mapping will return an\n    empty list.\n    \"\"\"\n    # For typing brevity we specify sources in Unix-style string form, then\n    # normalise them into the OS-specific form later.\n    extra_sources = {\n        'qutip.cy.spmatfuncs': ['qutip/cy/src/zspmv.cpp'],\n        'qutip.cy.openmp.parfuncs': ['qutip/cy/openmp/src/zspmv_openmp.cpp'],\n    }\n    out = collections.defaultdict(list)\n    for module, sources in extra_sources.items():\n        # Normalise the sources into OS-specific form.\n        out[module] = [str(pathlib.Path(source)) for source in sources]\n    return out\n\n\ndef create_extension_modules(options):\n    \"\"\"\n    Discover and Cythonise all extension modules that need to be built.  These\n    are returned so they can be passed into the setup command.\n    \"\"\"\n    out = []\n    root = pathlib.Path(options['rootdir'])\n    pyx_files = set(root.glob('qutip/**/*.pyx'))\n    if not options['openmp']:\n        pyx_files -= set(root.glob('qutip/**/openmp/**/*.pyx'))\n    extra_sources = _extension_extra_sources()\n    # Add Cython files from qutip\n    for pyx_file in pyx_files:\n        pyx_file = pyx_file.relative_to(root)\n        pyx_file_str = str(pyx_file)\n        if 'compiled_coeff' in pyx_file_str or 'qtcoeff_' in pyx_file_str:\n            # In development (at least for QuTiP ~4.5 and ~5.0) sometimes the\n            # Cythonised time-dependent coefficients would get dropped in the\n            # qutip directory if you weren't careful - this is just trying to\n            # minimise the occasional developer error.\n            warnings.warn(\n                \"skipping generated time-dependent coefficient: \"\n                + pyx_file_str\n            )\n            continue\n        # The module name is the same as the folder structure, but with dots in\n        # place of separators ('/' or '\\'), and without the '.pyx' extension.\n        pyx_module = \".\".join(pyx_file.parts)[:-4]\n        pyx_sources = [pyx_file_str] + extra_sources[pyx_module]\n        out.append(Extension(pyx_module,\n                             sources=pyx_sources,\n                             include_dirs=options['include'],\n                             extra_compile_args=options['cflags'],\n                             extra_link_args=options['ldflags'],\n                             language='c++'))\n    return cythonize(out)\n\n\ndef print_epilogue():\n    \"\"\"Display a post-setup epilogue.\"\"\"\n    longbar = \"=\"*80\n    message = \"\\n\".join([\n        longbar,\n        \"Installation complete\",\n        \"Please cite QuTiP in your publication.\",\n        longbar,\n        \"For your convenience a BibTeX reference can be easily generated with\",\n        \"`qutip.cite()`\",\n    ])\n    print(message)\n\n\nif __name__ == \"__main__\":\n    options = process_options()\n    create_version_py_file(options)\n    extensions = create_extension_modules(options)\n    # Most of the kwargs to setup are defined in setup.cfg; the only ones we\n    # keep here are ones that we have done some compile-time processing on.\n    setup(\n        version=options['version'],\n        ext_modules=extensions,\n        cmdclass={'build_ext': build_ext},\n    )\n    print_epilogue()\n", "path": "setup.py"}], "after_files": [{"content": "#!/usr/bin/env python\n\nimport collections\nimport os\nimport pathlib\nimport re\nimport subprocess\nimport sys\nimport sysconfig\nimport warnings\n\n# Required third-party imports, must be specified in pyproject.toml.\nimport packaging.version\nfrom setuptools import setup, Extension\nimport distutils.sysconfig\nimport numpy as np\nfrom Cython.Build import cythonize\nfrom Cython.Distutils import build_ext\n\n\ndef process_options():\n    \"\"\"\n    Determine all runtime options, returning a dictionary of the results.  The\n    keys are:\n        'rootdir': str\n            The root directory of the setup.  Almost certainly the directory\n            that this setup.py file is contained in.\n        'release': bool\n            Is this a release build (True) or a local development build (False)\n        'openmp': bool\n            Should we build our OpenMP extensions and attempt to link in OpenMP\n            libraries?\n        'cflags': list of str\n            Flags to be passed to the C++ compiler.\n        'ldflags': list of str\n            Flags to be passed to the linker.\n        'include': list of str\n            Additional directories to be added to the header files include\n            path.  These files will be detected by Cython as dependencies, so\n            changes to them will trigger recompilation of .pyx files, whereas\n            includes added in 'cflags' as '-I/path/to/include' may not.\n    \"\"\"\n    options = {}\n    options['rootdir'] = os.path.dirname(os.path.abspath(__file__))\n    options = _determine_user_arguments(options)\n    options = _determine_version(options)\n    options = _determine_compilation_options(options)\n    return options\n\n\ndef _determine_user_arguments(options):\n    \"\"\"\n    Add the 'openmp' option to the collection, based on the passed command-line\n    arguments or environment variables.\n    \"\"\"\n    options['openmp'] = (\n        '--with-openmp' in sys.argv\n        or bool(os.environ.get('CI_QUTIP_WITH_OPENMP'))\n    )\n    if \"--with-openmp\" in sys.argv:\n        sys.argv.remove(\"--with-openmp\")\n    return options\n\n\ndef _determine_compilation_options(options):\n    \"\"\"\n    Add additional options specific to C/C++ compilation.  These are 'cflags',\n    'ldflags' and 'include'.\n    \"\"\"\n    # Remove -Wstrict-prototypes from the CFLAGS variable that the Python build\n    # process uses in addition to user-specified ones; the flag is not valid\n    # for C++ compiles, but CFLAGS gets appended to those compiles anyway.\n    config = distutils.sysconfig.get_config_vars()\n    if \"CFLAGS\" in config:\n        config[\"CFLAGS\"] = config[\"CFLAGS\"].replace(\"-Wstrict-prototypes\", \"\")\n    options['cflags'] = []\n    options['ldflags'] = []\n    options['include'] = [np.get_include()]\n    if (\n        sysconfig.get_platform().startswith(\"win\")\n        and os.environ.get('MSYSTEM') is None\n    ):\n        # Visual Studio\n        options['cflags'].extend(['/w', '/Ox'])\n        if options['openmp']:\n            options['cflags'].append('/openmp')\n    else:\n        # Everything else\n        options['cflags'].extend(['-w', '-O3', '-funroll-loops'])\n    if sysconfig.get_platform().startswith(\"macos\"):\n        # These are needed for compiling on OSX 10.14+\n        options['cflags'].append('-mmacosx-version-min=10.9')\n        options['ldflags'].append('-mmacosx-version-min=10.9')\n        if options['openmp']:\n            options['cflags'].append('-fopenmp')\n            options['ldflags'].append('-fopenmp')\n    return options\n\n\ndef _determine_version(options):\n    \"\"\"\n    Adds the 'short_version', 'version' and 'release' options.\n\n    Read from the VERSION file to discover the version.  This should be a\n    single line file containing valid Python package public identifier (see PEP\n    440), for example\n      4.5.2rc2\n      5.0.0\n      5.1.1a1\n    We do that here rather than in setup.cfg so we can apply the local\n    versioning number as well.\n    \"\"\"\n    version_filename = os.path.join(options['rootdir'], 'VERSION')\n    with open(version_filename, \"r\") as version_file:\n        version_string = version_file.read().strip()\n    version = packaging.version.parse(version_string)\n    if isinstance(version, packaging.version.LegacyVersion):\n        raise ValueError(\"invalid version: \" + version_string)\n    options['short_version'] = str(version.public)\n    options['release'] = not version.is_devrelease\n    if not options['release']:\n        # Put the version string into canonical form, if it wasn't already.\n        version_string = str(version)\n        version_string += \"+\"\n        try:\n            git_out = subprocess.run(\n                ('git', 'rev-parse', '--verify', '--short=7', 'HEAD'),\n                check=True,\n                stdout=subprocess.PIPE, stderr=subprocess.PIPE,\n            )\n            git_hash = git_out.stdout.decode(sys.stdout.encoding).strip()\n            version_string += git_hash or \"nogit\"\n        # CalledProcessError is for if the git command fails for internal\n        # reasons (e.g. we're not in a git repository), OSError is for if\n        # something goes wrong when trying to run git (e.g. it's not installed,\n        # or a permission error).\n        except (subprocess.CalledProcessError, OSError):\n            version_string += \"nogit\"\n    options['version'] = version_string\n    return options\n\n\ndef create_version_py_file(options):\n    \"\"\"\n    Generate and write out the file qutip/version.py, which is used to produce\n    the '__version__' information for the module.  This function will overwrite\n    an existing file at that location.\n    \"\"\"\n    filename = os.path.join(options['rootdir'], 'qutip', 'version.py')\n    content = \"\\n\".join([\n        f\"# This file is automatically generated by QuTiP's setup.py.\",\n        f\"short_version = '{options['short_version']}'\",\n        f\"version = '{options['version']}'\",\n        f\"release = {options['release']}\",\n    ])\n    with open(filename, 'w') as file:\n        print(content, file=file)\n\n\ndef _extension_extra_sources():\n    \"\"\"\n    Get a mapping of {module: extra_sources} for all modules to be built.  The\n    module is the fully qualified Python module (e.g. 'qutip.cy.spmatfuncs'),\n    and extra_sources is a list of strings of relative paths to files.  If no\n    extra sources are known for a given module, the mapping will return an\n    empty list.\n    \"\"\"\n    # For typing brevity we specify sources in Unix-style string form, then\n    # normalise them into the OS-specific form later.\n    extra_sources = {\n        'qutip.cy.spmatfuncs': ['qutip/cy/src/zspmv.cpp'],\n        'qutip.cy.openmp.parfuncs': ['qutip/cy/openmp/src/zspmv_openmp.cpp'],\n    }\n    out = collections.defaultdict(list)\n    for module, sources in extra_sources.items():\n        # Normalise the sources into OS-specific form.\n        out[module] = [str(pathlib.Path(source)) for source in sources]\n    return out\n\n\ndef create_extension_modules(options):\n    \"\"\"\n    Discover and Cythonise all extension modules that need to be built.  These\n    are returned so they can be passed into the setup command.\n    \"\"\"\n    out = []\n    root = pathlib.Path(options['rootdir'])\n    pyx_files = set(root.glob('qutip/**/*.pyx'))\n    if not options['openmp']:\n        pyx_files -= set(root.glob('qutip/**/openmp/**/*.pyx'))\n    extra_sources = _extension_extra_sources()\n    # Add Cython files from qutip\n    for pyx_file in pyx_files:\n        pyx_file = pyx_file.relative_to(root)\n        pyx_file_str = str(pyx_file)\n        if 'compiled_coeff' in pyx_file_str or 'qtcoeff_' in pyx_file_str:\n            # In development (at least for QuTiP ~4.5 and ~5.0) sometimes the\n            # Cythonised time-dependent coefficients would get dropped in the\n            # qutip directory if you weren't careful - this is just trying to\n            # minimise the occasional developer error.\n            warnings.warn(\n                \"skipping generated time-dependent coefficient: \"\n                + pyx_file_str\n            )\n            continue\n        # The module name is the same as the folder structure, but with dots in\n        # place of separators ('/' or '\\'), and without the '.pyx' extension.\n        pyx_module = \".\".join(pyx_file.parts)[:-4]\n        pyx_sources = [pyx_file_str] + extra_sources[pyx_module]\n        out.append(Extension(pyx_module,\n                             sources=pyx_sources,\n                             include_dirs=options['include'],\n                             extra_compile_args=options['cflags'],\n                             extra_link_args=options['ldflags'],\n                             language='c++'))\n    return cythonize(out)\n\n\ndef print_epilogue():\n    \"\"\"Display a post-setup epilogue.\"\"\"\n    longbar = \"=\"*80\n    message = \"\\n\".join([\n        longbar,\n        \"Installation complete\",\n        \"Please cite QuTiP in your publication.\",\n        longbar,\n        \"For your convenience a BibTeX reference can be easily generated with\",\n        \"`qutip.cite()`\",\n    ])\n    print(message)\n\n\nif __name__ == \"__main__\":\n    options = process_options()\n    create_version_py_file(options)\n    extensions = create_extension_modules(options)\n    # Most of the kwargs to setup are defined in setup.cfg; the only ones we\n    # keep here are ones that we have done some compile-time processing on.\n    setup(\n        version=options['version'],\n        ext_modules=extensions,\n        cmdclass={'build_ext': build_ext},\n    )\n    print_epilogue()\n", "path": "setup.py"}]}