diff --git a/tests/serializers/test_yaml.py b/tests/serializers/test_yaml.py new file mode 100644 index 00000000000..d4e5c355782 --- /dev/null +++ b/tests/serializers/test_yaml.py @@ -0,0 +1,180 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +import importlib +import unittest + +from django.core import management, serializers +from django.core.serializers.base import DeserializationError +from django.test import SimpleTestCase, TestCase, TransactionTestCase +from django.utils import six +from django.utils.six import StringIO + +from .models import Author +from .tests import SerializersTestBase, SerializersTransactionTestBase + +try: + import yaml + HAS_YAML = True +except ImportError: + HAS_YAML = False + +YAML_IMPORT_ERROR_MESSAGE = r'No module named yaml' + + +class YamlImportModuleMock(object): + """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 + """ + 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 + """ + @classmethod + def setUpClass(cls): + """Removes imported yaml and stubs importlib.import_module""" + super(NoYamlSerializerTestCase, cls).setUpClass() + + 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""" + super(NoYamlSerializerTestCase, cls).tearDownClass() + + 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") + self.assertRaises(ImportError, serializers.serialize, "yaml", [jane]) + + def test_deserializer_pyyaml_error_message(self): + """Using yaml deserializer without pyyaml raises ImportError""" + self.assertRaises(ImportError, serializers.deserialize, "yaml", "") + + def test_dumpdata_pyyaml_error_message(self): + """Calling dumpdata produces an error when yaml package missing""" + with six.assertRaisesRegex(self, management.CommandError, YAML_IMPORT_ERROR_MESSAGE): + management.call_command('dumpdata', format='yaml') + + +@unittest.skipUnless(HAS_YAML, "No yaml library detected") +class YamlSerializerTestCase(SerializersTestBase, TestCase): + serializer_name = "yaml" + fwd_ref_str = """- fields: + headline: Forward references pose no problem + pub_date: 2006-06-16 15:00:00 + categories: [1] + author: 1 + pk: 1 + model: serializers.article +- fields: + name: Reference + pk: 1 + model: serializers.category +- fields: + name: Agnes + pk: 1 + model: serializers.author""" + + pkless_str = """- fields: + name: Reference + pk: null + model: serializers.category +- fields: + name: Non-fiction + model: serializers.category""" + + 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 + categories: [%(first_category_pk)s, %(second_category_pk)s] + meta_data: [] +""" + + @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 + if isinstance(field_value, six.string_types): + 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" + fwd_ref_str = """- fields: + headline: Forward references pose no problem + pub_date: 2006-06-16 15:00:00 + categories: [1] + author: 1 + pk: 1 + model: serializers.article +- fields: + name: Reference + pk: 1 + model: serializers.category +- fields: + name: Agnes + pk: 1 + model: serializers.author""" diff --git a/tests/serializers/tests.py b/tests/serializers/tests.py index 8c5555d35db..f92f0775d6e 100644 --- a/tests/serializers/tests.py +++ b/tests/serializers/tests.py @@ -1,14 +1,12 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -import importlib import json import re -import unittest from datetime import datetime from xml.dom import minidom -from django.core import management, serializers +from django.core import serializers from django.core.serializers.base import ProgressBar from django.db import connection, transaction from django.test import ( @@ -24,12 +22,6 @@ from .models import ( Team, ) -try: - import yaml - HAS_YAML = True -except ImportError: - HAS_YAML = False - @override_settings( SERIALIZATION_MODULES={ @@ -682,159 +674,3 @@ class JsonSerializerTransactionTestCase(SerializersTransactionTestBase, Transact "name": "Agnes" } }]""" - - -YAML_IMPORT_ERROR_MESSAGE = r'No module named yaml' - - -class YamlImportModuleMock(object): - """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 - """ - 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 - """ - @classmethod - def setUpClass(cls): - """Removes imported yaml and stubs importlib.import_module""" - super(NoYamlSerializerTestCase, cls).setUpClass() - - 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""" - super(NoYamlSerializerTestCase, cls).tearDownClass() - - 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") - self.assertRaises(ImportError, serializers.serialize, "yaml", [jane]) - - def test_deserializer_pyyaml_error_message(self): - """Using yaml deserializer without pyyaml raises ImportError""" - self.assertRaises(ImportError, serializers.deserialize, "yaml", "") - - def test_dumpdata_pyyaml_error_message(self): - """Calling dumpdata produces an error when yaml package missing""" - with six.assertRaisesRegex(self, management.CommandError, YAML_IMPORT_ERROR_MESSAGE): - management.call_command('dumpdata', format='yaml') - - -@unittest.skipUnless(HAS_YAML, "No yaml library detected") -class YamlSerializerTestCase(SerializersTestBase, TestCase): - serializer_name = "yaml" - fwd_ref_str = """- fields: - headline: Forward references pose no problem - pub_date: 2006-06-16 15:00:00 - categories: [1] - author: 1 - pk: 1 - model: serializers.article -- fields: - name: Reference - pk: 1 - model: serializers.category -- fields: - name: Agnes - pk: 1 - model: serializers.author""" - - pkless_str = """- fields: - name: Reference - pk: null - model: serializers.category -- fields: - name: Non-fiction - model: serializers.category""" - - 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 - categories: [%(first_category_pk)s, %(second_category_pk)s] - meta_data: [] -""" - - @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 - if isinstance(field_value, six.string_types): - ret_list.append(field_value) - else: - ret_list.append(str(field_value)) - return ret_list - - -@unittest.skipUnless(HAS_YAML, "No yaml library detected") -class YamlSerializerTransactionTestCase(SerializersTransactionTestBase, TransactionTestCase): - serializer_name = "yaml" - fwd_ref_str = """- fields: - headline: Forward references pose no problem - pub_date: 2006-06-16 15:00:00 - categories: [1] - author: 1 - pk: 1 - model: serializers.article -- fields: - name: Reference - pk: 1 - model: serializers.category -- fields: - name: Agnes - pk: 1 - model: serializers.author""" diff --git a/tests/serializers_regress/tests.py b/tests/serializers_regress/tests.py index 23837d17c0e..3da6ddafb42 100644 --- a/tests/serializers_regress/tests.py +++ b/tests/serializers_regress/tests.py @@ -11,7 +11,6 @@ from __future__ import unicode_literals import datetime import decimal import uuid -from unittest import skipUnless from django.core import serializers from django.core.serializers import SerializerDoesNotExist @@ -39,11 +38,6 @@ from .models import ( TextData, TimeData, UniqueAnchor, UUIDData, ) -try: - import yaml -except ImportError: - yaml = None - # A set of functions that can be used to recreate # test data objects of various kinds. # The save method is a raw base model save, to make @@ -433,12 +427,6 @@ class SerializerTests(TestCase): for obj in serializers.deserialize("json", """[{"pk":1}"""): pass - @skipUnless(yaml, "PyYAML not installed") - def test_yaml_deserializer_exception(self): - with self.assertRaises(DeserializationError): - for obj in serializers.deserialize("yaml", "{"): - pass - def test_serialize_proxy_model(self): BaseModel.objects.create(parent_data=1) base_objects = BaseModel.objects.all()