reqser.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. """
  2. Helper functions for serializing (and deserializing) requests.
  3. """
  4. import six
  5. from scrapy.http import Request
  6. from scrapy.utils.python import to_unicode, to_native_str
  7. from scrapy.utils.misc import load_object
  8. def request_to_dict(request, spider=None):
  9. """Convert Request object to a dict.
  10. If a spider is given, it will try to find out the name of the spider method
  11. used in the callback and store that as the callback.
  12. """
  13. cb = request.callback
  14. if callable(cb):
  15. cb = _find_method(spider, cb)
  16. eb = request.errback
  17. if callable(eb):
  18. eb = _find_method(spider, eb)
  19. d = {
  20. 'url': to_unicode(request.url), # urls should be safe (safe_string_url)
  21. 'callback': cb,
  22. 'errback': eb,
  23. 'method': request.method,
  24. 'headers': dict(request.headers),
  25. 'body': request.body,
  26. 'cookies': request.cookies,
  27. 'meta': request.meta,
  28. '_encoding': request._encoding,
  29. 'priority': request.priority,
  30. 'dont_filter': request.dont_filter,
  31. 'flags': request.flags,
  32. 'cb_kwargs': request.cb_kwargs,
  33. }
  34. if type(request) is not Request:
  35. d['_class'] = request.__module__ + '.' + request.__class__.__name__
  36. return d
  37. def request_from_dict(d, spider=None):
  38. """Create Request object from a dict.
  39. If a spider is given, it will try to resolve the callbacks looking at the
  40. spider for methods with the same name.
  41. """
  42. cb = d['callback']
  43. if cb and spider:
  44. cb = _get_method(spider, cb)
  45. eb = d['errback']
  46. if eb and spider:
  47. eb = _get_method(spider, eb)
  48. request_cls = load_object(d['_class']) if '_class' in d else Request
  49. return request_cls(
  50. url=to_native_str(d['url']),
  51. callback=cb,
  52. errback=eb,
  53. method=d['method'],
  54. headers=d['headers'],
  55. body=d['body'],
  56. cookies=d['cookies'],
  57. meta=d['meta'],
  58. encoding=d['_encoding'],
  59. priority=d['priority'],
  60. dont_filter=d['dont_filter'],
  61. flags=d.get('flags'),
  62. cb_kwargs=d.get('cb_kwargs'),
  63. )
  64. def _is_private_method(name):
  65. return name.startswith('__') and not name.endswith('__')
  66. def _mangle_private_name(obj, func, name):
  67. qualname = getattr(func, '__qualname__', None)
  68. if qualname is None:
  69. classname = obj.__class__.__name__.lstrip('_')
  70. return '_%s%s' % (classname, name)
  71. else:
  72. splits = qualname.split('.')
  73. return '_%s%s' % (splits[-2], splits[-1])
  74. def _find_method(obj, func):
  75. if obj:
  76. try:
  77. func_self = six.get_method_self(func)
  78. except AttributeError: # func has no __self__
  79. pass
  80. else:
  81. if func_self is obj:
  82. name = six.get_method_function(func).__name__
  83. if _is_private_method(name):
  84. return _mangle_private_name(obj, func, name)
  85. return name
  86. raise ValueError("Function %s is not a method of: %s" % (func, obj))
  87. def _get_method(obj, name):
  88. name = str(name)
  89. try:
  90. return getattr(obj, name)
  91. except AttributeError:
  92. raise ValueError("Method %r not found in: %s" % (name, obj))