We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Disk queues don't preserve Request class
When a Request subclass (e.g. FormRequest) is sent to a disk queue a bare Request is what you get back. 

This is inconvenient for scrapy-splash: Splash requests all have Splash URL as request.url, but for logging it is nice to display the requested URL, not only Splash URL. In scrapy-splash this is implemented by changing `__repr__` in a Request subclass, but it works only when request is kept in memory.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `scrapy/utils/reqser.py`
Content:
```
1 """
2 Helper functions for serializing (and deserializing) requests.
3 """
4 import six
5 
6 from scrapy.http import Request
7 from scrapy.utils.python import to_unicode, to_native_str
8 
9 
10 def request_to_dict(request, spider=None):
11     """Convert Request object to a dict.
12 
13     If a spider is given, it will try to find out the name of the spider method
14     used in the callback and store that as the callback.
15     """
16     cb = request.callback
17     if callable(cb):
18         cb = _find_method(spider, cb)
19     eb = request.errback
20     if callable(eb):
21         eb = _find_method(spider, eb)
22     d = {
23         'url': to_unicode(request.url),  # urls should be safe (safe_string_url)
24         'callback': cb,
25         'errback': eb,
26         'method': request.method,
27         'headers': dict(request.headers),
28         'body': request.body,
29         'cookies': request.cookies,
30         'meta': request.meta,
31         '_encoding': request._encoding,
32         'priority': request.priority,
33         'dont_filter': request.dont_filter,
34     }
35     return d
36 
37 
38 def request_from_dict(d, spider=None):
39     """Create Request object from a dict.
40 
41     If a spider is given, it will try to resolve the callbacks looking at the
42     spider for methods with the same name.
43     """
44     cb = d['callback']
45     if cb and spider:
46         cb = _get_method(spider, cb)
47     eb = d['errback']
48     if eb and spider:
49         eb = _get_method(spider, eb)
50     return Request(
51         url=to_native_str(d['url']),
52         callback=cb,
53         errback=eb,
54         method=d['method'],
55         headers=d['headers'],
56         body=d['body'],
57         cookies=d['cookies'],
58         meta=d['meta'],
59         encoding=d['_encoding'],
60         priority=d['priority'],
61         dont_filter=d['dont_filter'])
62 
63 
64 def _find_method(obj, func):
65     if obj:
66         try:
67             func_self = six.get_method_self(func)
68         except AttributeError:  # func has no __self__
69             pass
70         else:
71             if func_self is obj:
72                 return six.get_method_function(func).__name__
73     raise ValueError("Function %s is not a method of: %s" % (func, obj))
74 
75 
76 def _get_method(obj, name):
77     name = str(name)
78     try:
79         return getattr(obj, name)
80     except AttributeError:
81         raise ValueError("Method %r not found in: %s" % (name, obj))
82
```
--- 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/scrapy/utils/reqser.py b/scrapy/utils/reqser.py
--- a/scrapy/utils/reqser.py
+++ b/scrapy/utils/reqser.py
@@ -5,6 +5,7 @@
 
 from scrapy.http import Request
 from scrapy.utils.python import to_unicode, to_native_str
+from scrapy.utils.misc import load_object
 
 
 def request_to_dict(request, spider=None):
@@ -32,6 +33,8 @@
         'priority': request.priority,
         'dont_filter': request.dont_filter,
     }
+    if type(request) is not Request:
+        d['_class'] = request.__module__ + '.' + request.__class__.__name__
     return d
 
 
@@ -47,7 +50,8 @@
     eb = d['errback']
     if eb and spider:
         eb = _get_method(spider, eb)
-    return Request(
+    request_cls = load_object(d['_class']) if '_class' in d else Request
+    return request_cls(
         url=to_native_str(d['url']),
         callback=cb,
         errback=eb,

{"golden_diff": "diff --git a/scrapy/utils/reqser.py b/scrapy/utils/reqser.py\n--- a/scrapy/utils/reqser.py\n+++ b/scrapy/utils/reqser.py\n@@ -5,6 +5,7 @@\n \n from scrapy.http import Request\n from scrapy.utils.python import to_unicode, to_native_str\n+from scrapy.utils.misc import load_object\n \n \n def request_to_dict(request, spider=None):\n@@ -32,6 +33,8 @@\n         'priority': request.priority,\n         'dont_filter': request.dont_filter,\n     }\n+    if type(request) is not Request:\n+        d['_class'] = request.__module__ + '.' + request.__class__.__name__\n     return d\n \n \n@@ -47,7 +50,8 @@\n     eb = d['errback']\n     if eb and spider:\n         eb = _get_method(spider, eb)\n-    return Request(\n+    request_cls = load_object(d['_class']) if '_class' in d else Request\n+    return request_cls(\n         url=to_native_str(d['url']),\n         callback=cb,\n         errback=eb,\n", "issue": "Disk queues don't preserve Request class\nWhen a Request subclass (e.g. FormRequest) is sent to a disk queue a bare Request is what you get back. \n\nThis is inconvenient for scrapy-splash: Splash requests all have Splash URL as request.url, but for logging it is nice to display the requested URL, not only Splash URL. In scrapy-splash this is implemented by changing `__repr__` in a Request subclass, but it works only when request is kept in memory.\n\n", "before_files": [{"content": "\"\"\"\nHelper functions for serializing (and deserializing) requests.\n\"\"\"\nimport six\n\nfrom scrapy.http import Request\nfrom scrapy.utils.python import to_unicode, to_native_str\n\n\ndef request_to_dict(request, spider=None):\n    \"\"\"Convert Request object to a dict.\n\n    If a spider is given, it will try to find out the name of the spider method\n    used in the callback and store that as the callback.\n    \"\"\"\n    cb = request.callback\n    if callable(cb):\n        cb = _find_method(spider, cb)\n    eb = request.errback\n    if callable(eb):\n        eb = _find_method(spider, eb)\n    d = {\n        'url': to_unicode(request.url),  # urls should be safe (safe_string_url)\n        'callback': cb,\n        'errback': eb,\n        'method': request.method,\n        'headers': dict(request.headers),\n        'body': request.body,\n        'cookies': request.cookies,\n        'meta': request.meta,\n        '_encoding': request._encoding,\n        'priority': request.priority,\n        'dont_filter': request.dont_filter,\n    }\n    return d\n\n\ndef request_from_dict(d, spider=None):\n    \"\"\"Create Request object from a dict.\n\n    If a spider is given, it will try to resolve the callbacks looking at the\n    spider for methods with the same name.\n    \"\"\"\n    cb = d['callback']\n    if cb and spider:\n        cb = _get_method(spider, cb)\n    eb = d['errback']\n    if eb and spider:\n        eb = _get_method(spider, eb)\n    return Request(\n        url=to_native_str(d['url']),\n        callback=cb,\n        errback=eb,\n        method=d['method'],\n        headers=d['headers'],\n        body=d['body'],\n        cookies=d['cookies'],\n        meta=d['meta'],\n        encoding=d['_encoding'],\n        priority=d['priority'],\n        dont_filter=d['dont_filter'])\n\n\ndef _find_method(obj, func):\n    if obj:\n        try:\n            func_self = six.get_method_self(func)\n        except AttributeError:  # func has no __self__\n            pass\n        else:\n            if func_self is obj:\n                return six.get_method_function(func).__name__\n    raise ValueError(\"Function %s is not a method of: %s\" % (func, obj))\n\n\ndef _get_method(obj, name):\n    name = str(name)\n    try:\n        return getattr(obj, name)\n    except AttributeError:\n        raise ValueError(\"Method %r not found in: %s\" % (name, obj))\n", "path": "scrapy/utils/reqser.py"}], "after_files": [{"content": "\"\"\"\nHelper functions for serializing (and deserializing) requests.\n\"\"\"\nimport six\n\nfrom scrapy.http import Request\nfrom scrapy.utils.python import to_unicode, to_native_str\nfrom scrapy.utils.misc import load_object\n\n\ndef request_to_dict(request, spider=None):\n    \"\"\"Convert Request object to a dict.\n\n    If a spider is given, it will try to find out the name of the spider method\n    used in the callback and store that as the callback.\n    \"\"\"\n    cb = request.callback\n    if callable(cb):\n        cb = _find_method(spider, cb)\n    eb = request.errback\n    if callable(eb):\n        eb = _find_method(spider, eb)\n    d = {\n        'url': to_unicode(request.url),  # urls should be safe (safe_string_url)\n        'callback': cb,\n        'errback': eb,\n        'method': request.method,\n        'headers': dict(request.headers),\n        'body': request.body,\n        'cookies': request.cookies,\n        'meta': request.meta,\n        '_encoding': request._encoding,\n        'priority': request.priority,\n        'dont_filter': request.dont_filter,\n    }\n    if type(request) is not Request:\n        d['_class'] = request.__module__ + '.' + request.__class__.__name__\n    return d\n\n\ndef request_from_dict(d, spider=None):\n    \"\"\"Create Request object from a dict.\n\n    If a spider is given, it will try to resolve the callbacks looking at the\n    spider for methods with the same name.\n    \"\"\"\n    cb = d['callback']\n    if cb and spider:\n        cb = _get_method(spider, cb)\n    eb = d['errback']\n    if eb and spider:\n        eb = _get_method(spider, eb)\n    request_cls = load_object(d['_class']) if '_class' in d else Request\n    return request_cls(\n        url=to_native_str(d['url']),\n        callback=cb,\n        errback=eb,\n        method=d['method'],\n        headers=d['headers'],\n        body=d['body'],\n        cookies=d['cookies'],\n        meta=d['meta'],\n        encoding=d['_encoding'],\n        priority=d['priority'],\n        dont_filter=d['dont_filter'])\n\n\ndef _find_method(obj, func):\n    if obj:\n        try:\n            func_self = six.get_method_self(func)\n        except AttributeError:  # func has no __self__\n            pass\n        else:\n            if func_self is obj:\n                return six.get_method_function(func).__name__\n    raise ValueError(\"Function %s is not a method of: %s\" % (func, obj))\n\n\ndef _get_method(obj, name):\n    name = str(name)\n    try:\n        return getattr(obj, name)\n    except AttributeError:\n        raise ValueError(\"Method %r not found in: %s\" % (name, obj))\n", "path": "scrapy/utils/reqser.py"}]}