prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  OpenTracing plugin performs deepcopy of resolver's args, which fails when file upload for larger file is used.
  OpenTracing performs deep copy of arguments passed to the resolver function when args filtering is used (eg. to hide passwords), but this apparently fails there's larger uploaded file in the args.
  
  Potential fix would be default filter that replaces uploaded files with cheap str representation (eg. `<UploadedFile(name="test.jpg", type="image/jpeg", size=44100)>`) before custom filtering logic is ran next.
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `ariadne/contrib/tracing/opentracing.py`
  Content:
  ```
  1 from copy import deepcopy
  2 from functools import partial
  3 from inspect import isawaitable
  4 from typing import Any, Callable, Dict, Optional
  5 
  6 from graphql import GraphQLResolveInfo
  7 from opentracing import Scope, Tracer, global_tracer
  8 from opentracing.ext import tags
  9 
  10 from ...types import ContextValue, Extension, Resolver
  11 from .utils import format_path, should_trace
  12 
  13 ArgFilter = Callable[[Dict[str, Any], GraphQLResolveInfo], Dict[str, Any]]
  14 
  15 
  16 class OpenTracingExtension(Extension):
  17     _arg_filter: Optional[ArgFilter]
  18     _root_scope: Scope
  19     _tracer: Tracer
  20 
  21     def __init__(self, *, arg_filter: Optional[ArgFilter] = None):
  22         self._arg_filter = arg_filter
  23         self._tracer = global_tracer()
  24         self._root_scope = None
  25 
  26     def request_started(self, context: ContextValue):
  27         self._root_scope = self._tracer.start_active_span("GraphQL Query")
  28         self._root_scope.span.set_tag(tags.COMPONENT, "graphql")
  29 
  30     def request_finished(self, context: ContextValue):
  31         self._root_scope.close()
  32 
  33     async def resolve(
  34         self, next_: Resolver, parent: Any, info: GraphQLResolveInfo, **kwargs
  35     ):
  36         if not should_trace(info):
  37             result = next_(parent, info, **kwargs)
  38             if isawaitable(result):
  39                 result = await result
  40             return result
  41 
  42         with self._tracer.start_active_span(info.field_name) as scope:
  43             span = scope.span
  44             span.set_tag(tags.COMPONENT, "graphql")
  45             span.set_tag("graphql.parentType", info.parent_type.name)
  46 
  47             graphql_path = ".".join(
  48                 map(str, format_path(info.path))  # pylint: disable=bad-builtin
  49             )
  50             span.set_tag("graphql.path", graphql_path)
  51 
  52             if kwargs:
  53                 filtered_kwargs = self.filter_resolver_args(kwargs, info)
  54                 for kwarg, value in filtered_kwargs.items():
  55                     span.set_tag(f"graphql.param.{kwarg}", value)
  56 
  57             result = next_(parent, info, **kwargs)
  58             if isawaitable(result):
  59                 result = await result
  60             return result
  61 
  62     def filter_resolver_args(
  63         self, args: Dict[str, Any], info: GraphQLResolveInfo
  64     ) -> Dict[str, Any]:
  65         if not self._arg_filter:
  66             return args
  67 
  68         return self._arg_filter(deepcopy(args), info)
  69 
  70 
  71 class OpenTracingExtensionSync(OpenTracingExtension):
  72     def resolve(
  73         self, next_: Resolver, parent: Any, info: GraphQLResolveInfo, **kwargs
  74     ):  # pylint: disable=invalid-overridden-method
  75         if not should_trace(info):
  76             result = next_(parent, info, **kwargs)
  77             return result
  78 
  79         with self._tracer.start_active_span(info.field_name) as scope:
  80             span = scope.span
  81             span.set_tag(tags.COMPONENT, "graphql")
  82             span.set_tag("graphql.parentType", info.parent_type.name)
  83 
  84             graphql_path = ".".join(
  85                 map(str, format_path(info.path))  # pylint: disable=bad-builtin
  86             )
  87             span.set_tag("graphql.path", graphql_path)
  88 
  89             if kwargs:
  90                 filtered_kwargs = self.filter_resolver_args(kwargs, info)
  91                 for kwarg, value in filtered_kwargs.items():
  92                     span.set_tag(f"graphql.param.{kwarg}", value)
  93 
  94             result = next_(parent, info, **kwargs)
  95             return result
  96 
  97 
  98 def opentracing_extension(*, arg_filter: Optional[ArgFilter] = None):
  99     return partial(OpenTracingExtension, arg_filter=arg_filter)
  100 
  101 
  102 def opentracing_extension_sync(*, arg_filter: Optional[ArgFilter] = None):
  103     return partial(OpenTracingExtensionSync, arg_filter=arg_filter)
  104
  ```
  --- 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/ariadne/contrib/tracing/opentracing.py b/ariadne/contrib/tracing/opentracing.py
  --- a/ariadne/contrib/tracing/opentracing.py
  +++ b/ariadne/contrib/tracing/opentracing.py
  @@ -1,11 +1,13 @@
  -from copy import deepcopy
  +import cgi
  +import os
   from functools import partial
   from inspect import isawaitable
  -from typing import Any, Callable, Dict, Optional
  +from typing import Any, Callable, Dict, Optional, Union
   
   from graphql import GraphQLResolveInfo
   from opentracing import Scope, Tracer, global_tracer
   from opentracing.ext import tags
  +from starlette.datastructures import UploadFile
   
   from ...types import ContextValue, Extension, Resolver
   from .utils import format_path, should_trace
  @@ -62,10 +64,12 @@
       def filter_resolver_args(
           self, args: Dict[str, Any], info: GraphQLResolveInfo
       ) -> Dict[str, Any]:
  +        args_to_trace = copy_args_for_tracing(args)
  +
           if not self._arg_filter:
  -            return args
  +            return args_to_trace
   
  -        return self._arg_filter(deepcopy(args), info)
  +        return self._arg_filter(args_to_trace, info)
   
   
   class OpenTracingExtensionSync(OpenTracingExtension):
  @@ -101,3 +105,34 @@
   
   def opentracing_extension_sync(*, arg_filter: Optional[ArgFilter] = None):
       return partial(OpenTracingExtensionSync, arg_filter=arg_filter)
  +
  +
  +def copy_args_for_tracing(value: Any) -> Any:
  +    if isinstance(value, dict):
  +        return {k: copy_args_for_tracing(v) for k, v in value.items()}
  +    if isinstance(value, list):
  +        return [copy_args_for_tracing(v) for v in value]
  +    if isinstance(value, (UploadFile, cgi.FieldStorage)):
  +        return repr_upload_file(value)
  +    return value
  +
  +
  +def repr_upload_file(upload_file: Union[UploadFile, cgi.FieldStorage]) -> str:
  +    filename = upload_file.filename
  +
  +    if isinstance(upload_file, cgi.FieldStorage):
  +        mime_type = upload_file.type
  +    else:
  +        mime_type = upload_file.content_type
  +
  +    if upload_file.file is None and isinstance(upload_file, cgi.FieldStorage):
  +        size = len(upload_file.value) if upload_file.value is not None else 0
  +    else:
  +        file_ = upload_file.file
  +        file_.seek(0, os.SEEK_END)
  +        size = file_.tell()
  +        file_.seek(0)
  +
  +    return (
  +        f"{type(upload_file)}(mime_type={mime_type}, size={size}, filename={filename})"
  +    )
  
verification_info: {"golden_diff": "diff --git a/ariadne/contrib/tracing/opentracing.py b/ariadne/contrib/tracing/opentracing.py\n--- a/ariadne/contrib/tracing/opentracing.py\n+++ b/ariadne/contrib/tracing/opentracing.py\n@@ -1,11 +1,13 @@\n-from copy import deepcopy\n+import cgi\n+import os\n from functools import partial\n from inspect import isawaitable\n-from typing import Any, Callable, Dict, Optional\n+from typing import Any, Callable, Dict, Optional, Union\n \n from graphql import GraphQLResolveInfo\n from opentracing import Scope, Tracer, global_tracer\n from opentracing.ext import tags\n+from starlette.datastructures import UploadFile\n \n from ...types import ContextValue, Extension, Resolver\n from .utils import format_path, should_trace\n@@ -62,10 +64,12 @@\n     def filter_resolver_args(\n         self, args: Dict[str, Any], info: GraphQLResolveInfo\n     ) -> Dict[str, Any]:\n+        args_to_trace = copy_args_for_tracing(args)\n+\n         if not self._arg_filter:\n-            return args\n+            return args_to_trace\n \n-        return self._arg_filter(deepcopy(args), info)\n+        return self._arg_filter(args_to_trace, info)\n \n \n class OpenTracingExtensionSync(OpenTracingExtension):\n@@ -101,3 +105,34 @@\n \n def opentracing_extension_sync(*, arg_filter: Optional[ArgFilter] = None):\n     return partial(OpenTracingExtensionSync, arg_filter=arg_filter)\n+\n+\n+def copy_args_for_tracing(value: Any) -> Any:\n+    if isinstance(value, dict):\n+        return {k: copy_args_for_tracing(v) for k, v in value.items()}\n+    if isinstance(value, list):\n+        return [copy_args_for_tracing(v) for v in value]\n+    if isinstance(value, (UploadFile, cgi.FieldStorage)):\n+        return repr_upload_file(value)\n+    return value\n+\n+\n+def repr_upload_file(upload_file: Union[UploadFile, cgi.FieldStorage]) -> str:\n+    filename = upload_file.filename\n+\n+    if isinstance(upload_file, cgi.FieldStorage):\n+        mime_type = upload_file.type\n+    else:\n+        mime_type = upload_file.content_type\n+\n+    if upload_file.file is None and isinstance(upload_file, cgi.FieldStorage):\n+        size = len(upload_file.value) if upload_file.value is not None else 0\n+    else:\n+        file_ = upload_file.file\n+        file_.seek(0, os.SEEK_END)\n+        size = file_.tell()\n+        file_.seek(0)\n+\n+    return (\n+        f\"{type(upload_file)}(mime_type={mime_type}, size={size}, filename={filename})\"\n+    )\n", "issue": "OpenTracing plugin performs deepcopy of resolver's args, which fails when file upload for larger file is used.\nOpenTracing performs deep copy of arguments passed to the resolver function when args filtering is used (eg. to hide passwords), but this apparently fails there's larger uploaded file in the args.\r\n\r\nPotential fix would be default filter that replaces uploaded files with cheap str representation (eg. `<UploadedFile(name=\"test.jpg\", type=\"image/jpeg\", size=44100)>`) before custom filtering logic is ran next.\n", "before_files": [{"content": "from copy import deepcopy\nfrom functools import partial\nfrom inspect import isawaitable\nfrom typing import Any, Callable, Dict, Optional\n\nfrom graphql import GraphQLResolveInfo\nfrom opentracing import Scope, Tracer, global_tracer\nfrom opentracing.ext import tags\n\nfrom ...types import ContextValue, Extension, Resolver\nfrom .utils import format_path, should_trace\n\nArgFilter = Callable[[Dict[str, Any], GraphQLResolveInfo], Dict[str, Any]]\n\n\nclass OpenTracingExtension(Extension):\n    _arg_filter: Optional[ArgFilter]\n    _root_scope: Scope\n    _tracer: Tracer\n\n    def __init__(self, *, arg_filter: Optional[ArgFilter] = None):\n        self._arg_filter = arg_filter\n        self._tracer = global_tracer()\n        self._root_scope = None\n\n    def request_started(self, context: ContextValue):\n        self._root_scope = self._tracer.start_active_span(\"GraphQL Query\")\n        self._root_scope.span.set_tag(tags.COMPONENT, \"graphql\")\n\n    def request_finished(self, context: ContextValue):\n        self._root_scope.close()\n\n    async def resolve(\n        self, next_: Resolver, parent: Any, info: GraphQLResolveInfo, **kwargs\n    ):\n        if not should_trace(info):\n            result = next_(parent, info, **kwargs)\n            if isawaitable(result):\n                result = await result\n            return result\n\n        with self._tracer.start_active_span(info.field_name) as scope:\n            span = scope.span\n            span.set_tag(tags.COMPONENT, \"graphql\")\n            span.set_tag(\"graphql.parentType\", info.parent_type.name)\n\n            graphql_path = \".\".join(\n                map(str, format_path(info.path))  # pylint: disable=bad-builtin\n            )\n            span.set_tag(\"graphql.path\", graphql_path)\n\n            if kwargs:\n                filtered_kwargs = self.filter_resolver_args(kwargs, info)\n                for kwarg, value in filtered_kwargs.items():\n                    span.set_tag(f\"graphql.param.{kwarg}\", value)\n\n            result = next_(parent, info, **kwargs)\n            if isawaitable(result):\n                result = await result\n            return result\n\n    def filter_resolver_args(\n        self, args: Dict[str, Any], info: GraphQLResolveInfo\n    ) -> Dict[str, Any]:\n        if not self._arg_filter:\n            return args\n\n        return self._arg_filter(deepcopy(args), info)\n\n\nclass OpenTracingExtensionSync(OpenTracingExtension):\n    def resolve(\n        self, next_: Resolver, parent: Any, info: GraphQLResolveInfo, **kwargs\n    ):  # pylint: disable=invalid-overridden-method\n        if not should_trace(info):\n            result = next_(parent, info, **kwargs)\n            return result\n\n        with self._tracer.start_active_span(info.field_name) as scope:\n            span = scope.span\n            span.set_tag(tags.COMPONENT, \"graphql\")\n            span.set_tag(\"graphql.parentType\", info.parent_type.name)\n\n            graphql_path = \".\".join(\n                map(str, format_path(info.path))  # pylint: disable=bad-builtin\n            )\n            span.set_tag(\"graphql.path\", graphql_path)\n\n            if kwargs:\n                filtered_kwargs = self.filter_resolver_args(kwargs, info)\n                for kwarg, value in filtered_kwargs.items():\n                    span.set_tag(f\"graphql.param.{kwarg}\", value)\n\n            result = next_(parent, info, **kwargs)\n            return result\n\n\ndef opentracing_extension(*, arg_filter: Optional[ArgFilter] = None):\n    return partial(OpenTracingExtension, arg_filter=arg_filter)\n\n\ndef opentracing_extension_sync(*, arg_filter: Optional[ArgFilter] = None):\n    return partial(OpenTracingExtensionSync, arg_filter=arg_filter)\n", "path": "ariadne/contrib/tracing/opentracing.py"}], "after_files": [{"content": "import cgi\nimport os\nfrom functools import partial\nfrom inspect import isawaitable\nfrom typing import Any, Callable, Dict, Optional, Union\n\nfrom graphql import GraphQLResolveInfo\nfrom opentracing import Scope, Tracer, global_tracer\nfrom opentracing.ext import tags\nfrom starlette.datastructures import UploadFile\n\nfrom ...types import ContextValue, Extension, Resolver\nfrom .utils import format_path, should_trace\n\nArgFilter = Callable[[Dict[str, Any], GraphQLResolveInfo], Dict[str, Any]]\n\n\nclass OpenTracingExtension(Extension):\n    _arg_filter: Optional[ArgFilter]\n    _root_scope: Scope\n    _tracer: Tracer\n\n    def __init__(self, *, arg_filter: Optional[ArgFilter] = None):\n        self._arg_filter = arg_filter\n        self._tracer = global_tracer()\n        self._root_scope = None\n\n    def request_started(self, context: ContextValue):\n        self._root_scope = self._tracer.start_active_span(\"GraphQL Query\")\n        self._root_scope.span.set_tag(tags.COMPONENT, \"graphql\")\n\n    def request_finished(self, context: ContextValue):\n        self._root_scope.close()\n\n    async def resolve(\n        self, next_: Resolver, parent: Any, info: GraphQLResolveInfo, **kwargs\n    ):\n        if not should_trace(info):\n            result = next_(parent, info, **kwargs)\n            if isawaitable(result):\n                result = await result\n            return result\n\n        with self._tracer.start_active_span(info.field_name) as scope:\n            span = scope.span\n            span.set_tag(tags.COMPONENT, \"graphql\")\n            span.set_tag(\"graphql.parentType\", info.parent_type.name)\n\n            graphql_path = \".\".join(\n                map(str, format_path(info.path))  # pylint: disable=bad-builtin\n            )\n            span.set_tag(\"graphql.path\", graphql_path)\n\n            if kwargs:\n                filtered_kwargs = self.filter_resolver_args(kwargs, info)\n                for kwarg, value in filtered_kwargs.items():\n                    span.set_tag(f\"graphql.param.{kwarg}\", value)\n\n            result = next_(parent, info, **kwargs)\n            if isawaitable(result):\n                result = await result\n            return result\n\n    def filter_resolver_args(\n        self, args: Dict[str, Any], info: GraphQLResolveInfo\n    ) -> Dict[str, Any]:\n        args_to_trace = copy_args_for_tracing(args)\n\n        if not self._arg_filter:\n            return args_to_trace\n\n        return self._arg_filter(args_to_trace, info)\n\n\nclass OpenTracingExtensionSync(OpenTracingExtension):\n    def resolve(\n        self, next_: Resolver, parent: Any, info: GraphQLResolveInfo, **kwargs\n    ):  # pylint: disable=invalid-overridden-method\n        if not should_trace(info):\n            result = next_(parent, info, **kwargs)\n            return result\n\n        with self._tracer.start_active_span(info.field_name) as scope:\n            span = scope.span\n            span.set_tag(tags.COMPONENT, \"graphql\")\n            span.set_tag(\"graphql.parentType\", info.parent_type.name)\n\n            graphql_path = \".\".join(\n                map(str, format_path(info.path))  # pylint: disable=bad-builtin\n            )\n            span.set_tag(\"graphql.path\", graphql_path)\n\n            if kwargs:\n                filtered_kwargs = self.filter_resolver_args(kwargs, info)\n                for kwarg, value in filtered_kwargs.items():\n                    span.set_tag(f\"graphql.param.{kwarg}\", value)\n\n            result = next_(parent, info, **kwargs)\n            return result\n\n\ndef opentracing_extension(*, arg_filter: Optional[ArgFilter] = None):\n    return partial(OpenTracingExtension, arg_filter=arg_filter)\n\n\ndef opentracing_extension_sync(*, arg_filter: Optional[ArgFilter] = None):\n    return partial(OpenTracingExtensionSync, arg_filter=arg_filter)\n\n\ndef copy_args_for_tracing(value: Any) -> Any:\n    if isinstance(value, dict):\n        return {k: copy_args_for_tracing(v) for k, v in value.items()}\n    if isinstance(value, list):\n        return [copy_args_for_tracing(v) for v in value]\n    if isinstance(value, (UploadFile, cgi.FieldStorage)):\n        return repr_upload_file(value)\n    return value\n\n\ndef repr_upload_file(upload_file: Union[UploadFile, cgi.FieldStorage]) -> str:\n    filename = upload_file.filename\n\n    if isinstance(upload_file, cgi.FieldStorage):\n        mime_type = upload_file.type\n    else:\n        mime_type = upload_file.content_type\n\n    if upload_file.file is None and isinstance(upload_file, cgi.FieldStorage):\n        size = len(upload_file.value) if upload_file.value is not None else 0\n    else:\n        file_ = upload_file.file\n        file_.seek(0, os.SEEK_END)\n        size = file_.tell()\n        file_.seek(0)\n\n    return (\n        f\"{type(upload_file)}(mime_type={mime_type}, size={size}, filename={filename})\"\n    )\n", "path": "ariadne/contrib/tracing/opentracing.py"}]}