We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Software update fails on Debian testing/unstable
Tested with Octoprint 1.3.10

Right now, the software update will not work in Debian testing and unstable. The problem here is that Debian decided to name its python version `2.7.15+` (yes the '+' is part of the version string returned by `python --version`. Octoprint's version compare cannot cope with this and sees this as < 2.7.9 (which leads to a very confusing output of the software update component telling you why it doesn't want to update: `Python: 2.7.9 (you have: 2.7.15+)` ... took me some time to figure out what is actually going on)

There is a bug report for Debian's python2.7 package already here https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=914072
Sadly there is no feedback from the Debian maintainers on why they named it this way and if this might be changed again in the future.

--- 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/octoprint/util/version.py`
Content:
```
1 # coding=utf-8
2 """
3 This module provides a bunch of utility methods and helpers for version handling.
4 """
5 from __future__ import absolute_import, division, print_function
6 
7 __license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'
8 
9 import pkg_resources
10 import logging
11 
12 from octoprint import __version__
13 
14 
15 def get_octoprint_version_string():
16 	return __version__
17 
18 
19 def get_octoprint_version(base=False):
20 	octoprint_version_string = get_octoprint_version_string()
21 	return get_comparable_version(octoprint_version_string, base=base)
22 
23 
24 def is_released_octoprint_version(version=None):
25 	"""
26 	>>> import pkg_resources
27 	>>> is_released_octoprint_version(version=pkg_resources.parse_version("1.3.6rc3"))
28 	True
29 	>>> is_released_octoprint_version(version=pkg_resources.parse_version("1.3.6rc3.dev2+g1234"))
30 	False
31 	>>> is_released_octoprint_version(version=pkg_resources.parse_version("1.3.6"))
32 	True
33 	>>> is_released_octoprint_version(version=pkg_resources.parse_version("1.3.6.post1+g1234"))
34 	True
35 	>>> is_released_octoprint_version(version=pkg_resources.parse_version("1.3.6.post1.dev0+g1234"))
36 	False
37 	>>> is_released_octoprint_version(version=pkg_resources.parse_version("1.3.7.dev123+g23545"))
38 	False
39 	"""
40 
41 	if version is None:
42 		version = get_octoprint_version()
43 
44 	if isinstance(version, tuple):
45 		# old setuptools
46 		return "*@" not in version
47 	else:
48 		# new setuptools
49 		return "dev" not in version.public
50 
51 
52 def is_stable_octoprint_version(version=None):
53 	"""
54 	>>> import pkg_resources
55 	>>> is_stable_octoprint_version(version=pkg_resources.parse_version("1.3.6rc3"))
56 	False
57 	>>> is_stable_octoprint_version(version=pkg_resources.parse_version("1.3.6rc3.dev2+g1234"))
58 	False
59 	>>> is_stable_octoprint_version(version=pkg_resources.parse_version("1.3.6"))
60 	True
61 	>>> is_stable_octoprint_version(version=pkg_resources.parse_version("1.3.6.post1+g1234"))
62 	True
63 	>>> is_stable_octoprint_version(version=pkg_resources.parse_version("1.3.6.post1.dev0+g1234"))
64 	False
65 	>>> is_stable_octoprint_version(version=pkg_resources.parse_version("1.3.7.dev123+g23545"))
66 	False
67 	"""
68 
69 	if version is None:
70 		version = get_octoprint_version()
71 
72 	if not is_released_octoprint_version(version=version):
73 		return False
74 
75 	if isinstance(version, tuple):
76 		return "*a" not in version and "*b" not in version and "*c" not in version
77 	else:
78 		return not version.is_prerelease
79 
80 
81 def is_octoprint_compatible(*compatibility_entries, **kwargs):
82 	"""
83 	Tests if the current ``octoprint_version`` is compatible to any of the provided ``compatibility_entries``.
84 
85 	Arguments:
86 		compatibility_entries (str): compatibility string(s) to test against, result will be `True` if any match
87 			is found
88 		octoprint_version (tuple or SetuptoolsVersion): optional OctoPrint version to match against, if not current
89 			base version will be determined via :func:`get_octoprint_version`.
90 
91 	Returns:
92 		(bool) ``True`` if any of the provided compatibility entries matches or there are no entries, else ``False``
93 	"""
94 
95 	logger = logging.getLogger(__name__)
96 
97 	if not compatibility_entries:
98 		return True
99 
100 	octoprint_version = kwargs.get("octoprint_version")
101 	if octoprint_version is None:
102 		octoprint_version = get_octoprint_version(base=True)
103 
104 	for octo_compat in compatibility_entries:
105 		try:
106 			if not any(octo_compat.startswith(c) for c in ("<", "<=", "!=", "==", ">=", ">", "~=", "===")):
107 				octo_compat = ">={}".format(octo_compat)
108 
109 			s = pkg_resources.Requirement.parse("OctoPrint" + octo_compat)
110 			if octoprint_version in s:
111 				break
112 		except:
113 			logger.exception("Something is wrong with this compatibility string for OctoPrint: {}".format(octo_compat))
114 	else:
115 		return False
116 
117 	return True
118 
119 
120 def get_comparable_version(version_string, base=False):
121 	if "-" in version_string:
122 		version_string = version_string[:version_string.find("-")]
123 
124 	version = pkg_resources.parse_version(version_string)
125 
126 	# A leading v is common in github release tags and old setuptools doesn't remove it.
127 	if version and isinstance(version, tuple) and version[0].lower() == "*v":
128 		version = version[1:]
129 
130 	if base:
131 		if isinstance(version, tuple):
132 			# old setuptools
133 			base_version = []
134 			for part in version:
135 				if part.startswith("*"):
136 					break
137 				base_version.append(part)
138 			base_version.append("*final")
139 			version = tuple(base_version)
140 		else:
141 			# new setuptools
142 			version = pkg_resources.parse_version(version.base_version)
143 	return version
144
```
--- 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/octoprint/util/version.py b/src/octoprint/util/version.py
--- a/src/octoprint/util/version.py
+++ b/src/octoprint/util/version.py
@@ -121,6 +121,10 @@
 	if "-" in version_string:
 		version_string = version_string[:version_string.find("-")]
 
+	# Debian has the python version set to 2.7.15+ which is not PEP440 compliant (bug 914072)
+	if version_string.endswith("+"):
+		version_string = version_string[:-1]
+
 	version = pkg_resources.parse_version(version_string)
 
 	# A leading v is common in github release tags and old setuptools doesn't remove it.

{"golden_diff": "diff --git a/src/octoprint/util/version.py b/src/octoprint/util/version.py\n--- a/src/octoprint/util/version.py\n+++ b/src/octoprint/util/version.py\n@@ -121,6 +121,10 @@\n \tif \"-\" in version_string:\n \t\tversion_string = version_string[:version_string.find(\"-\")]\n \n+\t# Debian has the python version set to 2.7.15+ which is not PEP440 compliant (bug 914072)\n+\tif version_string.endswith(\"+\"):\n+\t\tversion_string = version_string[:-1]\n+\n \tversion = pkg_resources.parse_version(version_string)\n \n \t# A leading v is common in github release tags and old setuptools doesn't remove it.\n", "issue": "Software update fails on Debian testing/unstable\nTested with Octoprint 1.3.10\r\n\r\nRight now, the software update will not work in Debian testing and unstable. The problem here is that Debian decided to name its python version `2.7.15+` (yes the '+' is part of the version string returned by `python --version`. Octoprint's version compare cannot cope with this and sees this as < 2.7.9 (which leads to a very confusing output of the software update component telling you why it doesn't want to update: `Python: 2.7.9 (you have: 2.7.15+)` ... took me some time to figure out what is actually going on)\r\n\r\nThere is a bug report for Debian's python2.7 package already here https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=914072\r\nSadly there is no feedback from the Debian maintainers on why they named it this way and if this might be changed again in the future.\n", "before_files": [{"content": "# coding=utf-8\n\"\"\"\nThis module provides a bunch of utility methods and helpers for version handling.\n\"\"\"\nfrom __future__ import absolute_import, division, print_function\n\n__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'\n\nimport pkg_resources\nimport logging\n\nfrom octoprint import __version__\n\n\ndef get_octoprint_version_string():\n\treturn __version__\n\n\ndef get_octoprint_version(base=False):\n\toctoprint_version_string = get_octoprint_version_string()\n\treturn get_comparable_version(octoprint_version_string, base=base)\n\n\ndef is_released_octoprint_version(version=None):\n\t\"\"\"\n\t>>> import pkg_resources\n\t>>> is_released_octoprint_version(version=pkg_resources.parse_version(\"1.3.6rc3\"))\n\tTrue\n\t>>> is_released_octoprint_version(version=pkg_resources.parse_version(\"1.3.6rc3.dev2+g1234\"))\n\tFalse\n\t>>> is_released_octoprint_version(version=pkg_resources.parse_version(\"1.3.6\"))\n\tTrue\n\t>>> is_released_octoprint_version(version=pkg_resources.parse_version(\"1.3.6.post1+g1234\"))\n\tTrue\n\t>>> is_released_octoprint_version(version=pkg_resources.parse_version(\"1.3.6.post1.dev0+g1234\"))\n\tFalse\n\t>>> is_released_octoprint_version(version=pkg_resources.parse_version(\"1.3.7.dev123+g23545\"))\n\tFalse\n\t\"\"\"\n\n\tif version is None:\n\t\tversion = get_octoprint_version()\n\n\tif isinstance(version, tuple):\n\t\t# old setuptools\n\t\treturn \"*@\" not in version\n\telse:\n\t\t# new setuptools\n\t\treturn \"dev\" not in version.public\n\n\ndef is_stable_octoprint_version(version=None):\n\t\"\"\"\n\t>>> import pkg_resources\n\t>>> is_stable_octoprint_version(version=pkg_resources.parse_version(\"1.3.6rc3\"))\n\tFalse\n\t>>> is_stable_octoprint_version(version=pkg_resources.parse_version(\"1.3.6rc3.dev2+g1234\"))\n\tFalse\n\t>>> is_stable_octoprint_version(version=pkg_resources.parse_version(\"1.3.6\"))\n\tTrue\n\t>>> is_stable_octoprint_version(version=pkg_resources.parse_version(\"1.3.6.post1+g1234\"))\n\tTrue\n\t>>> is_stable_octoprint_version(version=pkg_resources.parse_version(\"1.3.6.post1.dev0+g1234\"))\n\tFalse\n\t>>> is_stable_octoprint_version(version=pkg_resources.parse_version(\"1.3.7.dev123+g23545\"))\n\tFalse\n\t\"\"\"\n\n\tif version is None:\n\t\tversion = get_octoprint_version()\n\n\tif not is_released_octoprint_version(version=version):\n\t\treturn False\n\n\tif isinstance(version, tuple):\n\t\treturn \"*a\" not in version and \"*b\" not in version and \"*c\" not in version\n\telse:\n\t\treturn not version.is_prerelease\n\n\ndef is_octoprint_compatible(*compatibility_entries, **kwargs):\n\t\"\"\"\n\tTests if the current ``octoprint_version`` is compatible to any of the provided ``compatibility_entries``.\n\n\tArguments:\n\t\tcompatibility_entries (str): compatibility string(s) to test against, result will be `True` if any match\n\t\t\tis found\n\t\toctoprint_version (tuple or SetuptoolsVersion): optional OctoPrint version to match against, if not current\n\t\t\tbase version will be determined via :func:`get_octoprint_version`.\n\n\tReturns:\n\t\t(bool) ``True`` if any of the provided compatibility entries matches or there are no entries, else ``False``\n\t\"\"\"\n\n\tlogger = logging.getLogger(__name__)\n\n\tif not compatibility_entries:\n\t\treturn True\n\n\toctoprint_version = kwargs.get(\"octoprint_version\")\n\tif octoprint_version is None:\n\t\toctoprint_version = get_octoprint_version(base=True)\n\n\tfor octo_compat in compatibility_entries:\n\t\ttry:\n\t\t\tif not any(octo_compat.startswith(c) for c in (\"<\", \"<=\", \"!=\", \"==\", \">=\", \">\", \"~=\", \"===\")):\n\t\t\t\tocto_compat = \">={}\".format(octo_compat)\n\n\t\t\ts = pkg_resources.Requirement.parse(\"OctoPrint\" + octo_compat)\n\t\t\tif octoprint_version in s:\n\t\t\t\tbreak\n\t\texcept:\n\t\t\tlogger.exception(\"Something is wrong with this compatibility string for OctoPrint: {}\".format(octo_compat))\n\telse:\n\t\treturn False\n\n\treturn True\n\n\ndef get_comparable_version(version_string, base=False):\n\tif \"-\" in version_string:\n\t\tversion_string = version_string[:version_string.find(\"-\")]\n\n\tversion = pkg_resources.parse_version(version_string)\n\n\t# A leading v is common in github release tags and old setuptools doesn't remove it.\n\tif version and isinstance(version, tuple) and version[0].lower() == \"*v\":\n\t\tversion = version[1:]\n\n\tif base:\n\t\tif isinstance(version, tuple):\n\t\t\t# old setuptools\n\t\t\tbase_version = []\n\t\t\tfor part in version:\n\t\t\t\tif part.startswith(\"*\"):\n\t\t\t\t\tbreak\n\t\t\t\tbase_version.append(part)\n\t\t\tbase_version.append(\"*final\")\n\t\t\tversion = tuple(base_version)\n\t\telse:\n\t\t\t# new setuptools\n\t\t\tversion = pkg_resources.parse_version(version.base_version)\n\treturn version\n", "path": "src/octoprint/util/version.py"}], "after_files": [{"content": "# coding=utf-8\n\"\"\"\nThis module provides a bunch of utility methods and helpers for version handling.\n\"\"\"\nfrom __future__ import absolute_import, division, print_function\n\n__license__ = 'GNU Affero General Public License http://www.gnu.org/licenses/agpl.html'\n\nimport pkg_resources\nimport logging\n\nfrom octoprint import __version__\n\n\ndef get_octoprint_version_string():\n\treturn __version__\n\n\ndef get_octoprint_version(base=False):\n\toctoprint_version_string = get_octoprint_version_string()\n\treturn get_comparable_version(octoprint_version_string, base=base)\n\n\ndef is_released_octoprint_version(version=None):\n\t\"\"\"\n\t>>> import pkg_resources\n\t>>> is_released_octoprint_version(version=pkg_resources.parse_version(\"1.3.6rc3\"))\n\tTrue\n\t>>> is_released_octoprint_version(version=pkg_resources.parse_version(\"1.3.6rc3.dev2+g1234\"))\n\tFalse\n\t>>> is_released_octoprint_version(version=pkg_resources.parse_version(\"1.3.6\"))\n\tTrue\n\t>>> is_released_octoprint_version(version=pkg_resources.parse_version(\"1.3.6.post1+g1234\"))\n\tTrue\n\t>>> is_released_octoprint_version(version=pkg_resources.parse_version(\"1.3.6.post1.dev0+g1234\"))\n\tFalse\n\t>>> is_released_octoprint_version(version=pkg_resources.parse_version(\"1.3.7.dev123+g23545\"))\n\tFalse\n\t\"\"\"\n\n\tif version is None:\n\t\tversion = get_octoprint_version()\n\n\tif isinstance(version, tuple):\n\t\t# old setuptools\n\t\treturn \"*@\" not in version\n\telse:\n\t\t# new setuptools\n\t\treturn \"dev\" not in version.public\n\n\ndef is_stable_octoprint_version(version=None):\n\t\"\"\"\n\t>>> import pkg_resources\n\t>>> is_stable_octoprint_version(version=pkg_resources.parse_version(\"1.3.6rc3\"))\n\tFalse\n\t>>> is_stable_octoprint_version(version=pkg_resources.parse_version(\"1.3.6rc3.dev2+g1234\"))\n\tFalse\n\t>>> is_stable_octoprint_version(version=pkg_resources.parse_version(\"1.3.6\"))\n\tTrue\n\t>>> is_stable_octoprint_version(version=pkg_resources.parse_version(\"1.3.6.post1+g1234\"))\n\tTrue\n\t>>> is_stable_octoprint_version(version=pkg_resources.parse_version(\"1.3.6.post1.dev0+g1234\"))\n\tFalse\n\t>>> is_stable_octoprint_version(version=pkg_resources.parse_version(\"1.3.7.dev123+g23545\"))\n\tFalse\n\t\"\"\"\n\n\tif version is None:\n\t\tversion = get_octoprint_version()\n\n\tif not is_released_octoprint_version(version=version):\n\t\treturn False\n\n\tif isinstance(version, tuple):\n\t\treturn \"*a\" not in version and \"*b\" not in version and \"*c\" not in version\n\telse:\n\t\treturn not version.is_prerelease\n\n\ndef is_octoprint_compatible(*compatibility_entries, **kwargs):\n\t\"\"\"\n\tTests if the current ``octoprint_version`` is compatible to any of the provided ``compatibility_entries``.\n\n\tArguments:\n\t\tcompatibility_entries (str): compatibility string(s) to test against, result will be `True` if any match\n\t\t\tis found\n\t\toctoprint_version (tuple or SetuptoolsVersion): optional OctoPrint version to match against, if not current\n\t\t\tbase version will be determined via :func:`get_octoprint_version`.\n\n\tReturns:\n\t\t(bool) ``True`` if any of the provided compatibility entries matches or there are no entries, else ``False``\n\t\"\"\"\n\n\tlogger = logging.getLogger(__name__)\n\n\tif not compatibility_entries:\n\t\treturn True\n\n\toctoprint_version = kwargs.get(\"octoprint_version\")\n\tif octoprint_version is None:\n\t\toctoprint_version = get_octoprint_version(base=True)\n\n\tfor octo_compat in compatibility_entries:\n\t\ttry:\n\t\t\tif not any(octo_compat.startswith(c) for c in (\"<\", \"<=\", \"!=\", \"==\", \">=\", \">\", \"~=\", \"===\")):\n\t\t\t\tocto_compat = \">={}\".format(octo_compat)\n\n\t\t\ts = pkg_resources.Requirement.parse(\"OctoPrint\" + octo_compat)\n\t\t\tif octoprint_version in s:\n\t\t\t\tbreak\n\t\texcept:\n\t\t\tlogger.exception(\"Something is wrong with this compatibility string for OctoPrint: {}\".format(octo_compat))\n\telse:\n\t\treturn False\n\n\treturn True\n\n\ndef get_comparable_version(version_string, base=False):\n\tif \"-\" in version_string:\n\t\tversion_string = version_string[:version_string.find(\"-\")]\n\n\t# Debian has the python version set to 2.7.15+ which is not PEP440 compliant (bug 914072)\n\tif version_string.endswith(\"+\"):\n\t\tversion_string = version_string[:-1]\n\n\tversion = pkg_resources.parse_version(version_string)\n\n\t# A leading v is common in github release tags and old setuptools doesn't remove it.\n\tif version and isinstance(version, tuple) and version[0].lower() == \"*v\":\n\t\tversion = version[1:]\n\n\tif base:\n\t\tif isinstance(version, tuple):\n\t\t\t# old setuptools\n\t\t\tbase_version = []\n\t\t\tfor part in version:\n\t\t\t\tif part.startswith(\"*\"):\n\t\t\t\t\tbreak\n\t\t\t\tbase_version.append(part)\n\t\t\tbase_version.append(\"*final\")\n\t\t\tversion = tuple(base_version)\n\t\telse:\n\t\t\t# new setuptools\n\t\t\tversion = pkg_resources.parse_version(version.base_version)\n\treturn version\n", "path": "src/octoprint/util/version.py"}]}