2015-09-26 16:43:12 +08:00
|
|
|
import importlib
|
|
|
|
import unittest
|
2017-01-07 19:11:46 +08:00
|
|
|
from io import StringIO
|
2015-09-26 16:43:12 +08:00
|
|
|
|
|
|
|
from django.core import management, serializers
|
|
|
|
from django.core.serializers.base import DeserializationError
|
|
|
|
from django.test import SimpleTestCase, TestCase, TransactionTestCase
|
|
|
|
|
|
|
|
from .models import Author
|
|
|
|
from .tests import SerializersTestBase, SerializersTransactionTestBase
|
|
|
|
|
|
|
|
try:
|
|
|
|
import yaml
|
2022-02-04 03:24:19 +08:00
|
|
|
|
2015-09-26 16:43:12 +08:00
|
|
|
HAS_YAML = True
|
|
|
|
except ImportError:
|
|
|
|
HAS_YAML = False
|
|
|
|
|
|
|
|
YAML_IMPORT_ERROR_MESSAGE = r"No module named yaml"
|
|
|
|
|
|
|
|
|
2017-01-19 15:39:46 +08:00
|
|
|
class YamlImportModuleMock:
|
2015-09-26 16:43:12 +08:00
|
|
|
"""Provides a wrapped import_module function to simulate yaml ImportError
|
|
|
|
|
|
|
|
In order to run tests that verify the behavior of the YAML serializer
|
|
|
|
when run on a system that has yaml installed (like the django CI server),
|
|
|
|
mock import_module, so that it raises an ImportError when the yaml
|
|
|
|
serializer is being imported. The importlib.import_module() call is
|
|
|
|
being made in the serializers.register_serializer().
|
|
|
|
|
|
|
|
Refs: #12756
|
|
|
|
"""
|
2022-02-04 03:24:19 +08:00
|
|
|
|
2015-09-26 16:43:12 +08:00
|
|
|
def __init__(self):
|
|
|
|
self._import_module = importlib.import_module
|
|
|
|
|
|
|
|
def import_module(self, module_path):
|
|
|
|
if module_path == serializers.BUILTIN_SERIALIZERS["yaml"]:
|
|
|
|
raise ImportError(YAML_IMPORT_ERROR_MESSAGE)
|
|
|
|
|
|
|
|
return self._import_module(module_path)
|
|
|
|
|
|
|
|
|
|
|
|
class NoYamlSerializerTestCase(SimpleTestCase):
|
|
|
|
"""Not having pyyaml installed provides a misleading error
|
|
|
|
|
|
|
|
Refs: #12756
|
|
|
|
"""
|
2022-02-04 03:24:19 +08:00
|
|
|
|
2015-09-26 16:43:12 +08:00
|
|
|
@classmethod
|
|
|
|
def setUpClass(cls):
|
|
|
|
"""Removes imported yaml and stubs importlib.import_module"""
|
2017-01-21 21:13:44 +08:00
|
|
|
super().setUpClass()
|
2015-09-26 16:43:12 +08:00
|
|
|
|
|
|
|
cls._import_module_mock = YamlImportModuleMock()
|
|
|
|
importlib.import_module = cls._import_module_mock.import_module
|
|
|
|
|
|
|
|
# clear out cached serializers to emulate yaml missing
|
|
|
|
serializers._serializers = {}
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def tearDownClass(cls):
|
|
|
|
"""Puts yaml back if necessary"""
|
2017-01-21 21:13:44 +08:00
|
|
|
super().tearDownClass()
|
2015-09-26 16:43:12 +08:00
|
|
|
|
|
|
|
importlib.import_module = cls._import_module_mock._import_module
|
|
|
|
|
|
|
|
# clear out cached serializers to clean out BadSerializer instances
|
|
|
|
serializers._serializers = {}
|
|
|
|
|
|
|
|
def test_serializer_pyyaml_error_message(self):
|
|
|
|
"""Using yaml serializer without pyyaml raises ImportError"""
|
|
|
|
jane = Author(name="Jane")
|
2016-01-17 19:26:39 +08:00
|
|
|
with self.assertRaises(ImportError):
|
|
|
|
serializers.serialize("yaml", [jane])
|
2015-09-26 16:43:12 +08:00
|
|
|
|
|
|
|
def test_deserializer_pyyaml_error_message(self):
|
|
|
|
"""Using yaml deserializer without pyyaml raises ImportError"""
|
2016-01-17 19:26:39 +08:00
|
|
|
with self.assertRaises(ImportError):
|
|
|
|
serializers.deserialize("yaml", "")
|
2015-09-26 16:43:12 +08:00
|
|
|
|
|
|
|
def test_dumpdata_pyyaml_error_message(self):
|
|
|
|
"""Calling dumpdata produces an error when yaml package missing"""
|
2016-01-18 16:45:45 +08:00
|
|
|
with self.assertRaisesMessage(
|
|
|
|
management.CommandError, YAML_IMPORT_ERROR_MESSAGE
|
|
|
|
):
|
2015-09-26 16:43:12 +08:00
|
|
|
management.call_command("dumpdata", format="yaml")
|
|
|
|
|
|
|
|
|
|
|
|
@unittest.skipUnless(HAS_YAML, "No yaml library detected")
|
|
|
|
class YamlSerializerTestCase(SerializersTestBase, TestCase):
|
|
|
|
serializer_name = "yaml"
|
2019-04-26 18:21:51 +08:00
|
|
|
pkless_str = """- model: serializers.category
|
2015-09-26 16:43:12 +08:00
|
|
|
pk: null
|
2019-04-26 18:21:51 +08:00
|
|
|
fields:
|
|
|
|
name: Reference
|
|
|
|
- model: serializers.category
|
|
|
|
fields:
|
|
|
|
name: Non-fiction"""
|
2015-09-26 16:43:12 +08:00
|
|
|
|
|
|
|
mapping_ordering_str = (
|
|
|
|
"""- model: serializers.article
|
|
|
|
pk: %(article_pk)s
|
|
|
|
fields:
|
|
|
|
author: %(author_pk)s
|
|
|
|
headline: Poker has no place on ESPN
|
|
|
|
pub_date: 2006-06-16 11:00:00
|
2019-03-14 03:06:47 +08:00
|
|
|
categories:"""
|
|
|
|
+ (
|
2019-03-20 21:07:49 +08:00
|
|
|
" [%(first_category_pk)s, %(second_category_pk)s]"
|
|
|
|
if HAS_YAML and yaml.__version__ < "5.1"
|
2019-03-14 03:06:47 +08:00
|
|
|
else "\n - %(first_category_pk)s\n - %(second_category_pk)s"
|
|
|
|
)
|
|
|
|
+ """
|
2015-09-26 16:43:12 +08:00
|
|
|
meta_data: []
|
2023-06-05 02:49:07 +08:00
|
|
|
topics: []
|
2015-09-26 16:43:12 +08:00
|
|
|
"""
|
2022-02-04 03:24:19 +08:00
|
|
|
)
|
2015-09-26 16:43:12 +08:00
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def _validate_output(serial_str):
|
|
|
|
try:
|
|
|
|
yaml.safe_load(StringIO(serial_str))
|
|
|
|
except Exception:
|
|
|
|
return False
|
|
|
|
else:
|
|
|
|
return True
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def _get_pk_values(serial_str):
|
|
|
|
ret_list = []
|
|
|
|
stream = StringIO(serial_str)
|
|
|
|
for obj_dict in yaml.safe_load(stream):
|
|
|
|
ret_list.append(obj_dict["pk"])
|
|
|
|
return ret_list
|
|
|
|
|
|
|
|
@staticmethod
|
|
|
|
def _get_field_values(serial_str, field_name):
|
|
|
|
ret_list = []
|
|
|
|
stream = StringIO(serial_str)
|
|
|
|
for obj_dict in yaml.safe_load(stream):
|
|
|
|
if "fields" in obj_dict and field_name in obj_dict["fields"]:
|
|
|
|
field_value = obj_dict["fields"][field_name]
|
|
|
|
# yaml.safe_load will return non-string objects for some
|
|
|
|
# of the fields we are interested in, this ensures that
|
|
|
|
# everything comes back as a string
|
2016-12-29 23:27:49 +08:00
|
|
|
if isinstance(field_value, str):
|
2015-09-26 16:43:12 +08:00
|
|
|
ret_list.append(field_value)
|
|
|
|
else:
|
|
|
|
ret_list.append(str(field_value))
|
|
|
|
return ret_list
|
|
|
|
|
|
|
|
def test_yaml_deserializer_exception(self):
|
|
|
|
with self.assertRaises(DeserializationError):
|
|
|
|
for obj in serializers.deserialize("yaml", "{"):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
@unittest.skipUnless(HAS_YAML, "No yaml library detected")
|
|
|
|
class YamlSerializerTransactionTestCase(
|
|
|
|
SerializersTransactionTestBase, TransactionTestCase
|
|
|
|
):
|
|
|
|
serializer_name = "yaml"
|
2019-04-26 18:21:51 +08:00
|
|
|
fwd_ref_str = """- model: serializers.article
|
|
|
|
pk: 1
|
|
|
|
fields:
|
2015-09-26 16:43:12 +08:00
|
|
|
headline: Forward references pose no problem
|
|
|
|
pub_date: 2006-06-16 15:00:00
|
|
|
|
categories: [1]
|
|
|
|
author: 1
|
2019-04-26 18:21:51 +08:00
|
|
|
- model: serializers.category
|
2015-09-26 16:43:12 +08:00
|
|
|
pk: 1
|
2019-04-26 18:21:51 +08:00
|
|
|
fields:
|
2015-09-26 16:43:12 +08:00
|
|
|
name: Reference
|
2019-04-26 18:21:51 +08:00
|
|
|
- model: serializers.author
|
2015-09-26 16:43:12 +08:00
|
|
|
pk: 1
|
2019-04-26 18:21:51 +08:00
|
|
|
fields:
|
|
|
|
name: Agnes"""
|