error_store.py 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. # -*- coding: utf-8 -*-
  2. """Utilities for storing collections of error messages.
  3. .. warning::
  4. This module is treated as private API.
  5. Users should not need to use this module directly.
  6. """
  7. from __future__ import unicode_literals
  8. from marshmallow.compat import iteritems
  9. from marshmallow.exceptions import SCHEMA
  10. class ErrorStore(object):
  11. def __init__(self):
  12. #: Dictionary of errors stored during serialization
  13. self.errors = {}
  14. #: True while (de)serializing a collection
  15. self._pending = False
  16. def store_error(self, messages, field_name=SCHEMA, index=None):
  17. # field error -> store/merge error messages under field name key
  18. # schema error -> if string or list, store/merge under _schema key
  19. # -> if dict, store/merge with other top-level keys
  20. if field_name != SCHEMA or not isinstance(messages, dict):
  21. messages = {field_name: messages}
  22. if index is not None:
  23. messages = {index: messages}
  24. self.errors = merge_errors(self.errors, messages)
  25. def merge_errors(errors1, errors2):
  26. """Deeply merge two error messages.
  27. The format of ``errors1`` and ``errors2`` matches the ``message``
  28. parameter of :exc:`marshmallow.exceptions.ValidationError`.
  29. """
  30. if not errors1:
  31. return errors2
  32. if not errors2:
  33. return errors1
  34. if isinstance(errors1, list):
  35. if isinstance(errors2, list):
  36. return errors1 + errors2
  37. if isinstance(errors2, dict):
  38. return dict(
  39. errors2,
  40. **{SCHEMA: merge_errors(errors1, errors2.get(SCHEMA))}
  41. )
  42. return errors1 + [errors2]
  43. if isinstance(errors1, dict):
  44. if isinstance(errors2, list):
  45. return dict(
  46. errors1,
  47. **{SCHEMA: merge_errors(errors1.get(SCHEMA), errors2)}
  48. )
  49. if isinstance(errors2, dict):
  50. errors = dict(errors1)
  51. for key, val in iteritems(errors2):
  52. if key in errors:
  53. errors[key] = merge_errors(errors[key], val)
  54. else:
  55. errors[key] = val
  56. return errors
  57. return dict(
  58. errors1,
  59. **{SCHEMA: merge_errors(errors1.get(SCHEMA), errors2)}
  60. )
  61. if isinstance(errors2, list):
  62. return [errors1] + errors2 if errors2 else errors1
  63. if isinstance(errors2, dict):
  64. return dict(
  65. errors2,
  66. **{SCHEMA: merge_errors(errors1, errors2.get(SCHEMA))}
  67. )
  68. return [errors1, errors2]