prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  False positive "Multiple candidiate toga backends"
  **Describe the bug**
  When using a development version of *toga*, a `RuntimeError` of multiple candidate toga backends is raised with the same backend. Stacktrace example:
  
  ```
  Traceback (most recent call last):
    File "C:\Users\sagi\AppData\Local\Programs\Python\Python310\lib\runpy.py", line 196, in _run_module_as_main
      return _run_code(code, main_globals, None,
    File "C:\Users\sagi\AppData\Local\Programs\Python\Python310\lib\runpy.py", line 86, in _run_code
      exec(code, run_globals)
    File "C:\Users\sagi\PycharmProjects\toga\examples\canvas\canvas\__main__.py", line 4, in <module>
      main().main_loop()
    File "C:\Users\sagi\PycharmProjects\toga\examples\canvas\canvas\app.py", line 565, in main
      return ExampleCanvasApp('Canvas', 'org.beeware.widgets.canvas')
    File "C:\Users\sagi\PycharmProjects\toga\src\core\src\toga\app.py", line 308, in __init__
      self.factory = get_platform_factory()
    File "C:\Users\sagi\PycharmProjects\toga\src\core\src\toga\platform.py", line 106, in get_platform_factory
      raise RuntimeError(
  RuntimeError: Multiple candidiate toga backends found: ('toga_winforms' (windows), 'toga_winforms' (windows)). Uninstall the backends you don't require, or use TOGA_BACKEND to specify a backend.
  ```
  
  **To Reproduce**
  Steps to reproduce the behavior:
  1. Open a new virtual environment
  2. Go to src\core
  3. Run `pip install -e .`
  4. Go to src\winforms
  5. Run `pip install -e .`
  6. Go to example\canvas (or any other example application)
  7. Run `python -m canvas`
  
  **Expected behavior**
  `RuntimeError` should not be raised in that case.
  
  **Environment:**
   - Operating System: Windows
   - Python version: 3.10.6
   - Software versions:
     - Briefcase: latest
     - Toga: latest
  
  
  --- 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/core/src/toga/platform.py`
  Content:
  ```
  1 import importlib
  2 import os
  3 import sys
  4 import warnings
  5 from functools import lru_cache
  6 
  7 try:
  8     # Usually, the pattern is "import module; if it doesn't exist,
  9     # import the shim". However, we need the 3.10 API for entry_points,
  10     # as the 3.8 didn't support the `groups` argument to entry_points.
  11     # Therefore, we try to import the compatibility shim first; and fall
  12     # back to the stdlib module if the shim isn't there.
  13     from importlib_metadata import entry_points
  14 except ImportError:
  15     from importlib.metadata import entry_points
  16 
  17 
  18 # Map python sys.platform with toga platforms names
  19 _TOGA_PLATFORMS = {
  20     'android': 'android',
  21     'darwin': 'macOS',
  22     'ios': 'iOS',
  23     'linux': 'linux',
  24     'tvos': 'tvOS',
  25     'watchos': 'watchOS',
  26     'wearos': 'wearOS',
  27     'emscripten': 'web',
  28     'win32': 'windows',
  29 }
  30 
  31 
  32 try:
  33     current_platform = os.environ['TOGA_PLATFORM']
  34 except KeyError:
  35     # Rely on `sys.getandroidapilevel`, which only exists on Android; see
  36     # https://github.com/beeware/Python-Android-support/issues/8
  37     if hasattr(sys, 'getandroidapilevel'):
  38         current_platform = 'android'
  39     else:
  40         current_platform = _TOGA_PLATFORMS.get(sys.platform)
  41 
  42 
  43 @lru_cache(maxsize=1)
  44 def get_platform_factory(factory=None):
  45     """ This function figures out what the current host platform is and
  46     imports the adequate factory. The factory is the interface to all platform
  47     specific implementations.
  48 
  49     If the TOGA_BACKEND environment variable is set, the factory will be loaded
  50     from that module.
  51 
  52     Returns: The suitable factory for the current host platform.
  53 
  54     Raises:
  55         RuntimeError: If no supported host platform can be identified.
  56     """
  57 
  58     ######################################################################
  59     # 2022-09: Backwards compatibility
  60     ######################################################################
  61     # factory no longer used
  62     if factory:
  63         warnings.warn("The factory argument is no longer used.", DeprecationWarning)
  64     ######################################################################
  65     # End backwards compatibility.
  66     ######################################################################
  67 
  68     toga_backends = entry_points(group='toga.backends')
  69     if not toga_backends:
  70         raise RuntimeError("No toga backend could be loaded.")
  71 
  72     backend_value = os.environ.get('TOGA_BACKEND')
  73     if backend_value:
  74         try:
  75             factory = importlib.import_module(f'{backend_value}.factory')
  76         except ModuleNotFoundError:
  77             toga_backends_values = ', '.join([f'{backend.value!r}' for backend in toga_backends])
  78             raise RuntimeError(
  79                 f"The backend specified by TOGA_BACKEND ({backend_value!r}) "
  80                 f"could not be loaded. It should be one of: {toga_backends_values}."
  81             )
  82     else:
  83         if len(toga_backends) == 1:
  84             backend = list(toga_backends)[0]
  85         else:
  86             # multiple backends are installed: choose the one that matches the host platform
  87             matching_backends = [
  88                 backend
  89                 for backend in toga_backends
  90                 if backend.name == current_platform
  91             ]
  92             if len(matching_backends) == 0:
  93                 toga_backends_string = ', '.join([
  94                     f'{backend.value!r} ({backend.name})'
  95                     for backend in toga_backends
  96                 ])
  97                 raise RuntimeError(
  98                     f"Multiple Toga backends are installed ({toga_backends_string}), "
  99                     f"but none of them match your current platform ({current_platform!r})."
  100                 )
  101             if len(matching_backends) > 1:
  102                 toga_backends_string = ', '.join([
  103                     f'{backend.value!r} ({backend.name})'
  104                     for backend in matching_backends
  105                 ])
  106                 raise RuntimeError(
  107                     f"Multiple candidiate toga backends found: ({toga_backends_string}). "
  108                     "Uninstall the backends you don't require, or use "
  109                     "TOGA_BACKEND to specify a backend."
  110                 )
  111             backend = matching_backends[0]
  112         factory = importlib.import_module(f'{backend.value}.factory')
  113     return factory
  114
  ```
  --- 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()
  
  ```
  
golden_diff: diff --git a/src/core/src/toga/platform.py b/src/core/src/toga/platform.py
  --- a/src/core/src/toga/platform.py
  +++ b/src/core/src/toga/platform.py
  @@ -67,7 +67,7 @@
   
       toga_backends = entry_points(group='toga.backends')
       if not toga_backends:
  -        raise RuntimeError("No toga backend could be loaded.")
  +        raise RuntimeError("No Toga backend could be loaded.")
   
       backend_value = os.environ.get('TOGA_BACKEND')
       if backend_value:
  @@ -80,8 +80,14 @@
                   f"could not be loaded. It should be one of: {toga_backends_values}."
               )
       else:
  +        # As of Setuptools 65.5, entry points are returned duplicated if the
  +        # package is installed editable. Use a set to ensure that each entry point
  +        # is only returned once.
  +        # See https://github.com/pypa/setuptools/issues/3649
  +        toga_backends = sorted(set(toga_backends))
  +
           if len(toga_backends) == 1:
  -            backend = list(toga_backends)[0]
  +            backend = toga_backends[0]
           else:
               # multiple backends are installed: choose the one that matches the host platform
               matching_backends = [
  
verification_info: {"golden_diff": "diff --git a/src/core/src/toga/platform.py b/src/core/src/toga/platform.py\n--- a/src/core/src/toga/platform.py\n+++ b/src/core/src/toga/platform.py\n@@ -67,7 +67,7 @@\n \n     toga_backends = entry_points(group='toga.backends')\n     if not toga_backends:\n-        raise RuntimeError(\"No toga backend could be loaded.\")\n+        raise RuntimeError(\"No Toga backend could be loaded.\")\n \n     backend_value = os.environ.get('TOGA_BACKEND')\n     if backend_value:\n@@ -80,8 +80,14 @@\n                 f\"could not be loaded. It should be one of: {toga_backends_values}.\"\n             )\n     else:\n+        # As of Setuptools 65.5, entry points are returned duplicated if the\n+        # package is installed editable. Use a set to ensure that each entry point\n+        # is only returned once.\n+        # See https://github.com/pypa/setuptools/issues/3649\n+        toga_backends = sorted(set(toga_backends))\n+\n         if len(toga_backends) == 1:\n-            backend = list(toga_backends)[0]\n+            backend = toga_backends[0]\n         else:\n             # multiple backends are installed: choose the one that matches the host platform\n             matching_backends = [\n", "issue": "False positive \"Multiple candidiate toga backends\"\n**Describe the bug**\r\nWhen using a development version of *toga*, a `RuntimeError` of multiple candidate toga backends is raised with the same backend. Stacktrace example:\r\n\r\n```\r\nTraceback (most recent call last):\r\n  File \"C:\\Users\\sagi\\AppData\\Local\\Programs\\Python\\Python310\\lib\\runpy.py\", line 196, in _run_module_as_main\r\n    return _run_code(code, main_globals, None,\r\n  File \"C:\\Users\\sagi\\AppData\\Local\\Programs\\Python\\Python310\\lib\\runpy.py\", line 86, in _run_code\r\n    exec(code, run_globals)\r\n  File \"C:\\Users\\sagi\\PycharmProjects\\toga\\examples\\canvas\\canvas\\__main__.py\", line 4, in <module>\r\n    main().main_loop()\r\n  File \"C:\\Users\\sagi\\PycharmProjects\\toga\\examples\\canvas\\canvas\\app.py\", line 565, in main\r\n    return ExampleCanvasApp('Canvas', 'org.beeware.widgets.canvas')\r\n  File \"C:\\Users\\sagi\\PycharmProjects\\toga\\src\\core\\src\\toga\\app.py\", line 308, in __init__\r\n    self.factory = get_platform_factory()\r\n  File \"C:\\Users\\sagi\\PycharmProjects\\toga\\src\\core\\src\\toga\\platform.py\", line 106, in get_platform_factory\r\n    raise RuntimeError(\r\nRuntimeError: Multiple candidiate toga backends found: ('toga_winforms' (windows), 'toga_winforms' (windows)). Uninstall the backends you don't require, or use TOGA_BACKEND to specify a backend.\r\n```\r\n\r\n**To Reproduce**\r\nSteps to reproduce the behavior:\r\n1. Open a new virtual environment\r\n2. Go to src\\core\r\n3. Run `pip install -e .`\r\n4. Go to src\\winforms\r\n5. Run `pip install -e .`\r\n6. Go to example\\canvas (or any other example application)\r\n7. Run `python -m canvas`\r\n\r\n**Expected behavior**\r\n`RuntimeError` should not be raised in that case.\r\n\r\n**Environment:**\r\n - Operating System: Windows\r\n - Python version: 3.10.6\r\n - Software versions:\r\n   - Briefcase: latest\r\n   - Toga: latest\r\n\n", "before_files": [{"content": "import importlib\nimport os\nimport sys\nimport warnings\nfrom functools import lru_cache\n\ntry:\n    # Usually, the pattern is \"import module; if it doesn't exist,\n    # import the shim\". However, we need the 3.10 API for entry_points,\n    # as the 3.8 didn't support the `groups` argument to entry_points.\n    # Therefore, we try to import the compatibility shim first; and fall\n    # back to the stdlib module if the shim isn't there.\n    from importlib_metadata import entry_points\nexcept ImportError:\n    from importlib.metadata import entry_points\n\n\n# Map python sys.platform with toga platforms names\n_TOGA_PLATFORMS = {\n    'android': 'android',\n    'darwin': 'macOS',\n    'ios': 'iOS',\n    'linux': 'linux',\n    'tvos': 'tvOS',\n    'watchos': 'watchOS',\n    'wearos': 'wearOS',\n    'emscripten': 'web',\n    'win32': 'windows',\n}\n\n\ntry:\n    current_platform = os.environ['TOGA_PLATFORM']\nexcept KeyError:\n    # Rely on `sys.getandroidapilevel`, which only exists on Android; see\n    # https://github.com/beeware/Python-Android-support/issues/8\n    if hasattr(sys, 'getandroidapilevel'):\n        current_platform = 'android'\n    else:\n        current_platform = _TOGA_PLATFORMS.get(sys.platform)\n\n\n@lru_cache(maxsize=1)\ndef get_platform_factory(factory=None):\n    \"\"\" This function figures out what the current host platform is and\n    imports the adequate factory. The factory is the interface to all platform\n    specific implementations.\n\n    If the TOGA_BACKEND environment variable is set, the factory will be loaded\n    from that module.\n\n    Returns: The suitable factory for the current host platform.\n\n    Raises:\n        RuntimeError: If no supported host platform can be identified.\n    \"\"\"\n\n    ######################################################################\n    # 2022-09: Backwards compatibility\n    ######################################################################\n    # factory no longer used\n    if factory:\n        warnings.warn(\"The factory argument is no longer used.\", DeprecationWarning)\n    ######################################################################\n    # End backwards compatibility.\n    ######################################################################\n\n    toga_backends = entry_points(group='toga.backends')\n    if not toga_backends:\n        raise RuntimeError(\"No toga backend could be loaded.\")\n\n    backend_value = os.environ.get('TOGA_BACKEND')\n    if backend_value:\n        try:\n            factory = importlib.import_module(f'{backend_value}.factory')\n        except ModuleNotFoundError:\n            toga_backends_values = ', '.join([f'{backend.value!r}' for backend in toga_backends])\n            raise RuntimeError(\n                f\"The backend specified by TOGA_BACKEND ({backend_value!r}) \"\n                f\"could not be loaded. It should be one of: {toga_backends_values}.\"\n            )\n    else:\n        if len(toga_backends) == 1:\n            backend = list(toga_backends)[0]\n        else:\n            # multiple backends are installed: choose the one that matches the host platform\n            matching_backends = [\n                backend\n                for backend in toga_backends\n                if backend.name == current_platform\n            ]\n            if len(matching_backends) == 0:\n                toga_backends_string = ', '.join([\n                    f'{backend.value!r} ({backend.name})'\n                    for backend in toga_backends\n                ])\n                raise RuntimeError(\n                    f\"Multiple Toga backends are installed ({toga_backends_string}), \"\n                    f\"but none of them match your current platform ({current_platform!r}).\"\n                )\n            if len(matching_backends) > 1:\n                toga_backends_string = ', '.join([\n                    f'{backend.value!r} ({backend.name})'\n                    for backend in matching_backends\n                ])\n                raise RuntimeError(\n                    f\"Multiple candidiate toga backends found: ({toga_backends_string}). \"\n                    \"Uninstall the backends you don't require, or use \"\n                    \"TOGA_BACKEND to specify a backend.\"\n                )\n            backend = matching_backends[0]\n        factory = importlib.import_module(f'{backend.value}.factory')\n    return factory\n", "path": "src/core/src/toga/platform.py"}], "after_files": [{"content": "import importlib\nimport os\nimport sys\nimport warnings\nfrom functools import lru_cache\n\ntry:\n    # Usually, the pattern is \"import module; if it doesn't exist,\n    # import the shim\". However, we need the 3.10 API for entry_points,\n    # as the 3.8 didn't support the `groups` argument to entry_points.\n    # Therefore, we try to import the compatibility shim first; and fall\n    # back to the stdlib module if the shim isn't there.\n    from importlib_metadata import entry_points\nexcept ImportError:\n    from importlib.metadata import entry_points\n\n\n# Map python sys.platform with toga platforms names\n_TOGA_PLATFORMS = {\n    'android': 'android',\n    'darwin': 'macOS',\n    'ios': 'iOS',\n    'linux': 'linux',\n    'tvos': 'tvOS',\n    'watchos': 'watchOS',\n    'wearos': 'wearOS',\n    'emscripten': 'web',\n    'win32': 'windows',\n}\n\n\ntry:\n    current_platform = os.environ['TOGA_PLATFORM']\nexcept KeyError:\n    # Rely on `sys.getandroidapilevel`, which only exists on Android; see\n    # https://github.com/beeware/Python-Android-support/issues/8\n    if hasattr(sys, 'getandroidapilevel'):\n        current_platform = 'android'\n    else:\n        current_platform = _TOGA_PLATFORMS.get(sys.platform)\n\n\n@lru_cache(maxsize=1)\ndef get_platform_factory(factory=None):\n    \"\"\" This function figures out what the current host platform is and\n    imports the adequate factory. The factory is the interface to all platform\n    specific implementations.\n\n    If the TOGA_BACKEND environment variable is set, the factory will be loaded\n    from that module.\n\n    Returns: The suitable factory for the current host platform.\n\n    Raises:\n        RuntimeError: If no supported host platform can be identified.\n    \"\"\"\n\n    ######################################################################\n    # 2022-09: Backwards compatibility\n    ######################################################################\n    # factory no longer used\n    if factory:\n        warnings.warn(\"The factory argument is no longer used.\", DeprecationWarning)\n    ######################################################################\n    # End backwards compatibility.\n    ######################################################################\n\n    toga_backends = entry_points(group='toga.backends')\n    if not toga_backends:\n        raise RuntimeError(\"No Toga backend could be loaded.\")\n\n    backend_value = os.environ.get('TOGA_BACKEND')\n    if backend_value:\n        try:\n            factory = importlib.import_module(f'{backend_value}.factory')\n        except ModuleNotFoundError:\n            toga_backends_values = ', '.join([f'{backend.value!r}' for backend in toga_backends])\n            raise RuntimeError(\n                f\"The backend specified by TOGA_BACKEND ({backend_value!r}) \"\n                f\"could not be loaded. It should be one of: {toga_backends_values}.\"\n            )\n    else:\n        # As of Setuptools 65.5, entry points are returned duplicated if the\n        # package is installed editable. Use a set to ensure that each entry point\n        # is only returned once.\n        # See https://github.com/pypa/setuptools/issues/3649\n        toga_backends = sorted(set(toga_backends))\n\n        if len(toga_backends) == 1:\n            backend = toga_backends[0]\n        else:\n            # multiple backends are installed: choose the one that matches the host platform\n            matching_backends = [\n                backend\n                for backend in toga_backends\n                if backend.name == current_platform\n            ]\n            if len(matching_backends) == 0:\n                toga_backends_string = ', '.join([\n                    f'{backend.value!r} ({backend.name})'\n                    for backend in toga_backends\n                ])\n                raise RuntimeError(\n                    f\"Multiple Toga backends are installed ({toga_backends_string}), \"\n                    f\"but none of them match your current platform ({current_platform!r}).\"\n                )\n            if len(matching_backends) > 1:\n                toga_backends_string = ', '.join([\n                    f'{backend.value!r} ({backend.name})'\n                    for backend in matching_backends\n                ])\n                raise RuntimeError(\n                    f\"Multiple candidiate toga backends found: ({toga_backends_string}). \"\n                    \"Uninstall the backends you don't require, or use \"\n                    \"TOGA_BACKEND to specify a backend.\"\n                )\n            backend = matching_backends[0]\n        factory = importlib.import_module(f'{backend.value}.factory')\n    return factory\n", "path": "src/core/src/toga/platform.py"}]}