pyyaml.py 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. """
  2. YAML serializer.
  3. Requires PyYaml (http://pyyaml.org/), but that's checked for in __init__.
  4. """
  5. import decimal
  6. import yaml
  7. import sys
  8. from io import StringIO
  9. from django.db import models
  10. from django.core.serializers.base import DeserializationError
  11. from django.core.serializers.python import Serializer as PythonSerializer
  12. from django.core.serializers.python import Deserializer as PythonDeserializer
  13. from django.utils import six
  14. # Use the C (faster) implementation if possible
  15. try:
  16. from yaml import CSafeLoader as SafeLoader
  17. from yaml import CSafeDumper as SafeDumper
  18. except ImportError:
  19. from yaml import SafeLoader, SafeDumper
  20. class DjangoSafeDumper(SafeDumper):
  21. def represent_decimal(self, data):
  22. return self.represent_scalar('tag:yaml.org,2002:str', str(data))
  23. DjangoSafeDumper.add_representer(decimal.Decimal, DjangoSafeDumper.represent_decimal)
  24. class Serializer(PythonSerializer):
  25. """
  26. Convert a queryset to YAML.
  27. """
  28. internal_use_only = False
  29. def handle_field(self, obj, field):
  30. # A nasty special case: base YAML doesn't support serialization of time
  31. # types (as opposed to dates or datetimes, which it does support). Since
  32. # we want to use the "safe" serializer for better interoperability, we
  33. # need to do something with those pesky times. Converting 'em to strings
  34. # isn't perfect, but it's better than a "!!python/time" type which would
  35. # halt deserialization under any other language.
  36. if isinstance(field, models.TimeField) and getattr(obj, field.name) is not None:
  37. self._current[field.name] = str(getattr(obj, field.name))
  38. else:
  39. super(Serializer, self).handle_field(obj, field)
  40. def end_serialization(self):
  41. yaml.dump(self.objects, self.stream, Dumper=DjangoSafeDumper, **self.options)
  42. def getvalue(self):
  43. # Grand-parent super
  44. return super(PythonSerializer, self).getvalue()
  45. def Deserializer(stream_or_string, **options):
  46. """
  47. Deserialize a stream or string of YAML data.
  48. """
  49. if isinstance(stream_or_string, bytes):
  50. stream_or_string = stream_or_string.decode('utf-8')
  51. if isinstance(stream_or_string, six.string_types):
  52. stream = StringIO(stream_or_string)
  53. else:
  54. stream = stream_or_string
  55. try:
  56. for obj in PythonDeserializer(yaml.load(stream, Loader=SafeLoader), **options):
  57. yield obj
  58. except GeneratorExit:
  59. raise
  60. except Exception as e:
  61. # Map to deserializer error
  62. six.reraise(DeserializationError, DeserializationError(e), sys.exc_info()[2])