prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  object has no attribute '__qualname__'
  I am getting the following error when trying to enable the scout APM on a starlette application:
  ```
  Traceback (most recent call last):
    File "/app/.heroku/python/lib/python3.8/site-packages/uvicorn/protocols/http/httptools_impl.py", line 391, in run_asgi
      result = await app(self.scope, self.receive, self.send)
    File "/app/.heroku/python/lib/python3.8/site-packages/uvicorn/middleware/proxy_headers.py", line 45, in __call__
      return await self.app(scope, receive, send)
    File "/app/.heroku/python/lib/python3.8/site-packages/starlette/applications.py", line 111, in __call__
      await self.middleware_stack(scope, receive, send)
    File "/app/.heroku/python/lib/python3.8/site-packages/starlette/middleware/errors.py", line 181, in __call__
      raise exc from None
    File "/app/.heroku/python/lib/python3.8/site-packages/starlette/middleware/errors.py", line 159, in __call__
      await self.app(scope, receive, _send)
    File "/app/.heroku/python/lib/python3.8/site-packages/scout_apm/async_/starlette.py", line 67, in __call__
      grab_extra_data()
    File "/app/.heroku/python/lib/python3.8/site-packages/scout_apm/async_/starlette.py", line 35, in grab_extra_data
      endpoint.__module__, endpoint.__qualname__
  AttributeError: 'GraphQLWithBackground' object has no attribute '__qualname__'
  ```
  
  `GraphQLWithBackground` is a subclass of `ariadne.asgi.GraphQL`.
  
  --- 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/scout_apm/async_/starlette.py`
  Content:
  ```
  1 # coding=utf-8
  2 from __future__ import absolute_import, division, print_function, unicode_literals
  3 
  4 import wrapt
  5 from starlette.background import BackgroundTask
  6 
  7 import scout_apm.core
  8 from scout_apm.core.tracked_request import TrackedRequest
  9 from scout_apm.core.web_requests import asgi_track_request_data
  10 
  11 
  12 class ScoutMiddleware:
  13     def __init__(self, app):
  14         self.app = app
  15         installed = scout_apm.core.install()
  16         self._do_nothing = not installed
  17         if installed:
  18             install_background_instrumentation()
  19 
  20     async def __call__(self, scope, receive, send):
  21         if self._do_nothing or scope["type"] != "http":
  22             return await self.app(scope, receive, send)
  23 
  24         tracked_request = TrackedRequest.instance()
  25         # Can't name controller until post-routing - see final clause
  26         controller_span = tracked_request.start_span(operation="Controller/Unknown")
  27 
  28         asgi_track_request_data(scope, tracked_request)
  29 
  30         def grab_extra_data():
  31             if "endpoint" in scope:
  32                 # Rename top span
  33                 endpoint = scope["endpoint"]
  34                 controller_span.operation = "Controller/{}.{}".format(
  35                     endpoint.__module__, endpoint.__qualname__
  36                 )
  37                 tracked_request.is_real_request = True
  38 
  39             # From AuthenticationMiddleware - bypass request.user because it
  40             # throws AssertionError if 'user' is not in Scope, and we need a
  41             # try/except already
  42             try:
  43                 username = scope["user"].display_name
  44             except (KeyError, AttributeError):
  45                 pass
  46             else:
  47                 tracked_request.tag("username", username)
  48 
  49         async def wrapped_send(data):
  50             type_ = data.get("type", None)
  51             if type_ == "http.response.start" and 500 <= data.get("status", 200) <= 599:
  52                 tracked_request.tag("error", "true")
  53             elif type_ == "http.response.body" and not data.get("more_body", False):
  54                 # Finish HTTP span when body finishes sending, not later (e.g.
  55                 # after background tasks)
  56                 grab_extra_data()
  57                 tracked_request.stop_span()
  58             return await send(data)
  59 
  60         try:
  61             await self.app(scope, receive, wrapped_send)
  62         except Exception as exc:
  63             tracked_request.tag("error", "true")
  64             raise exc
  65         finally:
  66             if tracked_request.end_time is None:
  67                 grab_extra_data()
  68                 tracked_request.stop_span()
  69 
  70 
  71 background_instrumentation_installed = False
  72 
  73 
  74 def install_background_instrumentation():
  75     global background_instrumentation_installed
  76     if background_instrumentation_installed:
  77         return
  78     background_instrumentation_installed = True
  79 
  80     @wrapt.decorator
  81     async def wrapped_background_call(wrapped, instance, args, kwargs):
  82         tracked_request = TrackedRequest.instance()
  83         tracked_request.is_real_request = True
  84 
  85         with tracked_request.span(
  86             operation="Job/{}.{}".format(
  87                 instance.func.__module__, instance.func.__qualname__
  88             )
  89         ):
  90             return await wrapped(*args, **kwargs)
  91 
  92     BackgroundTask.__call__ = wrapped_background_call(BackgroundTask.__call__)
  93
  ```
  --- 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/scout_apm/async_/starlette.py b/src/scout_apm/async_/starlette.py
  --- a/src/scout_apm/async_/starlette.py
  +++ b/src/scout_apm/async_/starlette.py
  @@ -31,8 +31,11 @@
               if "endpoint" in scope:
                   # Rename top span
                   endpoint = scope["endpoint"]
  +                if not hasattr(endpoint, "__qualname__"):
  +                    endpoint = endpoint.__class__
                   controller_span.operation = "Controller/{}.{}".format(
  -                    endpoint.__module__, endpoint.__qualname__
  +                    endpoint.__module__,
  +                    endpoint.__qualname__,
                   )
                   tracked_request.is_real_request = True
  
verification_info: {"golden_diff": "diff --git a/src/scout_apm/async_/starlette.py b/src/scout_apm/async_/starlette.py\n--- a/src/scout_apm/async_/starlette.py\n+++ b/src/scout_apm/async_/starlette.py\n@@ -31,8 +31,11 @@\n             if \"endpoint\" in scope:\n                 # Rename top span\n                 endpoint = scope[\"endpoint\"]\n+                if not hasattr(endpoint, \"__qualname__\"):\n+                    endpoint = endpoint.__class__\n                 controller_span.operation = \"Controller/{}.{}\".format(\n-                    endpoint.__module__, endpoint.__qualname__\n+                    endpoint.__module__,\n+                    endpoint.__qualname__,\n                 )\n                 tracked_request.is_real_request = True\n", "issue": "object has no attribute '__qualname__'\nI am getting the following error when trying to enable the scout APM on a starlette application:\r\n```\r\nTraceback (most recent call last):\r\n  File \"/app/.heroku/python/lib/python3.8/site-packages/uvicorn/protocols/http/httptools_impl.py\", line 391, in run_asgi\r\n    result = await app(self.scope, self.receive, self.send)\r\n  File \"/app/.heroku/python/lib/python3.8/site-packages/uvicorn/middleware/proxy_headers.py\", line 45, in __call__\r\n    return await self.app(scope, receive, send)\r\n  File \"/app/.heroku/python/lib/python3.8/site-packages/starlette/applications.py\", line 111, in __call__\r\n    await self.middleware_stack(scope, receive, send)\r\n  File \"/app/.heroku/python/lib/python3.8/site-packages/starlette/middleware/errors.py\", line 181, in __call__\r\n    raise exc from None\r\n  File \"/app/.heroku/python/lib/python3.8/site-packages/starlette/middleware/errors.py\", line 159, in __call__\r\n    await self.app(scope, receive, _send)\r\n  File \"/app/.heroku/python/lib/python3.8/site-packages/scout_apm/async_/starlette.py\", line 67, in __call__\r\n    grab_extra_data()\r\n  File \"/app/.heroku/python/lib/python3.8/site-packages/scout_apm/async_/starlette.py\", line 35, in grab_extra_data\r\n    endpoint.__module__, endpoint.__qualname__\r\nAttributeError: 'GraphQLWithBackground' object has no attribute '__qualname__'\r\n```\r\n\r\n`GraphQLWithBackground` is a subclass of `ariadne.asgi.GraphQL`.\n", "before_files": [{"content": "# coding=utf-8\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\nimport wrapt\nfrom starlette.background import BackgroundTask\n\nimport scout_apm.core\nfrom scout_apm.core.tracked_request import TrackedRequest\nfrom scout_apm.core.web_requests import asgi_track_request_data\n\n\nclass ScoutMiddleware:\n    def __init__(self, app):\n        self.app = app\n        installed = scout_apm.core.install()\n        self._do_nothing = not installed\n        if installed:\n            install_background_instrumentation()\n\n    async def __call__(self, scope, receive, send):\n        if self._do_nothing or scope[\"type\"] != \"http\":\n            return await self.app(scope, receive, send)\n\n        tracked_request = TrackedRequest.instance()\n        # Can't name controller until post-routing - see final clause\n        controller_span = tracked_request.start_span(operation=\"Controller/Unknown\")\n\n        asgi_track_request_data(scope, tracked_request)\n\n        def grab_extra_data():\n            if \"endpoint\" in scope:\n                # Rename top span\n                endpoint = scope[\"endpoint\"]\n                controller_span.operation = \"Controller/{}.{}\".format(\n                    endpoint.__module__, endpoint.__qualname__\n                )\n                tracked_request.is_real_request = True\n\n            # From AuthenticationMiddleware - bypass request.user because it\n            # throws AssertionError if 'user' is not in Scope, and we need a\n            # try/except already\n            try:\n                username = scope[\"user\"].display_name\n            except (KeyError, AttributeError):\n                pass\n            else:\n                tracked_request.tag(\"username\", username)\n\n        async def wrapped_send(data):\n            type_ = data.get(\"type\", None)\n            if type_ == \"http.response.start\" and 500 <= data.get(\"status\", 200) <= 599:\n                tracked_request.tag(\"error\", \"true\")\n            elif type_ == \"http.response.body\" and not data.get(\"more_body\", False):\n                # Finish HTTP span when body finishes sending, not later (e.g.\n                # after background tasks)\n                grab_extra_data()\n                tracked_request.stop_span()\n            return await send(data)\n\n        try:\n            await self.app(scope, receive, wrapped_send)\n        except Exception as exc:\n            tracked_request.tag(\"error\", \"true\")\n            raise exc\n        finally:\n            if tracked_request.end_time is None:\n                grab_extra_data()\n                tracked_request.stop_span()\n\n\nbackground_instrumentation_installed = False\n\n\ndef install_background_instrumentation():\n    global background_instrumentation_installed\n    if background_instrumentation_installed:\n        return\n    background_instrumentation_installed = True\n\n    @wrapt.decorator\n    async def wrapped_background_call(wrapped, instance, args, kwargs):\n        tracked_request = TrackedRequest.instance()\n        tracked_request.is_real_request = True\n\n        with tracked_request.span(\n            operation=\"Job/{}.{}\".format(\n                instance.func.__module__, instance.func.__qualname__\n            )\n        ):\n            return await wrapped(*args, **kwargs)\n\n    BackgroundTask.__call__ = wrapped_background_call(BackgroundTask.__call__)\n", "path": "src/scout_apm/async_/starlette.py"}], "after_files": [{"content": "# coding=utf-8\nfrom __future__ import absolute_import, division, print_function, unicode_literals\n\nimport wrapt\nfrom starlette.background import BackgroundTask\n\nimport scout_apm.core\nfrom scout_apm.core.tracked_request import TrackedRequest\nfrom scout_apm.core.web_requests import asgi_track_request_data\n\n\nclass ScoutMiddleware:\n    def __init__(self, app):\n        self.app = app\n        installed = scout_apm.core.install()\n        self._do_nothing = not installed\n        if installed:\n            install_background_instrumentation()\n\n    async def __call__(self, scope, receive, send):\n        if self._do_nothing or scope[\"type\"] != \"http\":\n            return await self.app(scope, receive, send)\n\n        tracked_request = TrackedRequest.instance()\n        # Can't name controller until post-routing - see final clause\n        controller_span = tracked_request.start_span(operation=\"Controller/Unknown\")\n\n        asgi_track_request_data(scope, tracked_request)\n\n        def grab_extra_data():\n            if \"endpoint\" in scope:\n                # Rename top span\n                endpoint = scope[\"endpoint\"]\n                if not hasattr(endpoint, \"__qualname__\"):\n                    endpoint = endpoint.__class__\n                controller_span.operation = \"Controller/{}.{}\".format(\n                    endpoint.__module__,\n                    endpoint.__qualname__,\n                )\n                tracked_request.is_real_request = True\n\n            # From AuthenticationMiddleware - bypass request.user because it\n            # throws AssertionError if 'user' is not in Scope, and we need a\n            # try/except already\n            try:\n                username = scope[\"user\"].display_name\n            except (KeyError, AttributeError):\n                pass\n            else:\n                tracked_request.tag(\"username\", username)\n\n        async def wrapped_send(data):\n            type_ = data.get(\"type\", None)\n            if type_ == \"http.response.start\" and 500 <= data.get(\"status\", 200) <= 599:\n                tracked_request.tag(\"error\", \"true\")\n            elif type_ == \"http.response.body\" and not data.get(\"more_body\", False):\n                # Finish HTTP span when body finishes sending, not later (e.g.\n                # after background tasks)\n                grab_extra_data()\n                tracked_request.stop_span()\n            return await send(data)\n\n        try:\n            await self.app(scope, receive, wrapped_send)\n        except Exception as exc:\n            tracked_request.tag(\"error\", \"true\")\n            raise exc\n        finally:\n            if tracked_request.end_time is None:\n                grab_extra_data()\n                tracked_request.stop_span()\n\n\nbackground_instrumentation_installed = False\n\n\ndef install_background_instrumentation():\n    global background_instrumentation_installed\n    if background_instrumentation_installed:\n        return\n    background_instrumentation_installed = True\n\n    @wrapt.decorator\n    async def wrapped_background_call(wrapped, instance, args, kwargs):\n        tracked_request = TrackedRequest.instance()\n        tracked_request.is_real_request = True\n\n        with tracked_request.span(\n            operation=\"Job/{}.{}\".format(\n                instance.func.__module__, instance.func.__qualname__\n            )\n        ):\n            return await wrapped(*args, **kwargs)\n\n    BackgroundTask.__call__ = wrapped_background_call(BackgroundTask.__call__)\n", "path": "src/scout_apm/async_/starlette.py"}]}