123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261 |
- import decimal
- import json
- import re
- from django.core import serializers
- from django.core.serializers.base import DeserializationError
- from django.db import models
- from django.test import TestCase, TransactionTestCase
- from django.test.utils import isolate_apps
- from .models import Score
- from .tests import SerializersTestBase, SerializersTransactionTestBase
- class JsonlSerializerTestCase(SerializersTestBase, TestCase):
- serializer_name = "jsonl"
- pkless_str = [
- '{"pk": null,"model": "serializers.category","fields": {"name": "Reference"}}',
- '{"model": "serializers.category","fields": {"name": "Non-fiction"}}',
- ]
- pkless_str = "\n".join([s.replace("\n", "") for s in pkless_str])
- 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-16T11:00:00",'
- '"categories": [%(first_category_pk)s,%(second_category_pk)s],'
- '"meta_data": []}}\n'
- )
- @staticmethod
- def _validate_output(serial_str):
- try:
- for line in serial_str.split("\n"):
- if line:
- json.loads(line)
- except Exception:
- return False
- else:
- return True
- @staticmethod
- def _get_pk_values(serial_str):
- serial_list = [json.loads(line) for line in serial_str.split("\n") if line]
- return [obj_dict['pk'] for obj_dict in serial_list]
- @staticmethod
- def _get_field_values(serial_str, field_name):
- serial_list = [json.loads(line) for line in serial_str.split("\n") if line]
- return [obj_dict['fields'][field_name] for obj_dict in serial_list if field_name in obj_dict['fields']]
- def test_no_indentation(self):
- s = serializers.jsonl.Serializer()
- json_data = s.serialize([Score(score=5.0), Score(score=6.0)], indent=2)
- for line in json_data.splitlines():
- self.assertIsNone(re.search(r'.+,\s*$', line))
- @isolate_apps('serializers')
- def test_custom_encoder(self):
- class ScoreDecimal(models.Model):
- score = models.DecimalField()
- class CustomJSONEncoder(json.JSONEncoder):
- def default(self, o):
- if isinstance(o, decimal.Decimal):
- return str(o)
- return super().default(o)
- s = serializers.jsonl.Serializer()
- json_data = s.serialize(
- [ScoreDecimal(score=decimal.Decimal(1.0))], cls=CustomJSONEncoder,
- )
- self.assertIn('"fields": {"score": "1"}', json_data)
- def test_json_deserializer_exception(self):
- with self.assertRaises(DeserializationError):
- for obj in serializers.deserialize("jsonl", """[{"pk":1}"""):
- pass
- def test_helpful_error_message_invalid_pk(self):
- """
- If there is an invalid primary key, the error message contains the
- model associated with it.
- """
- test_string = (
- '{"pk": "badpk","model": "serializers.player",'
- '"fields": {"name": "Bob","rank": 1,"team": "Team"}}'
- )
- with self.assertRaisesMessage(DeserializationError, "(serializers.player:pk=badpk)"):
- list(serializers.deserialize('jsonl', test_string))
- def test_helpful_error_message_invalid_field(self):
- """
- If there is an invalid field value, the error message contains the
- model associated with it.
- """
- test_string = (
- '{"pk": "1","model": "serializers.player",'
- '"fields": {"name": "Bob","rank": "invalidint","team": "Team"}}'
- )
- expected = "(serializers.player:pk=1) field_value was 'invalidint'"
- with self.assertRaisesMessage(DeserializationError, expected):
- list(serializers.deserialize('jsonl', test_string))
- def test_helpful_error_message_for_foreign_keys(self):
- """
- Invalid foreign keys with a natural key throws a helpful error message,
- such as what the failing key is.
- """
- test_string = (
- '{"pk": 1, "model": "serializers.category",'
- '"fields": {'
- '"name": "Unknown foreign key",'
- '"meta_data": ["doesnotexist","metadata"]}}'
- )
- key = ["doesnotexist", "metadata"]
- expected = "(serializers.category:pk=1) field_value was '%r'" % key
- with self.assertRaisesMessage(DeserializationError, expected):
- list(serializers.deserialize('jsonl', test_string))
- def test_helpful_error_message_for_many2many_non_natural(self):
- """
- Invalid many-to-many keys throws a helpful error message.
- """
- test_strings = [
- """{
- "pk": 1,
- "model": "serializers.article",
- "fields": {
- "author": 1,
- "headline": "Unknown many to many",
- "pub_date": "2014-09-15T10:35:00",
- "categories": [1, "doesnotexist"]
- }
- }""",
- """{
- "pk": 1,
- "model": "serializers.author",
- "fields": {"name": "Agnes"}
- }""",
- """{
- "pk": 1,
- "model": "serializers.category",
- "fields": {"name": "Reference"}
- }"""
- ]
- test_string = "\n".join([s.replace("\n", "") for s in test_strings])
- expected = "(serializers.article:pk=1) field_value was 'doesnotexist'"
- with self.assertRaisesMessage(DeserializationError, expected):
- list(serializers.deserialize('jsonl', test_string))
- def test_helpful_error_message_for_many2many_natural1(self):
- """
- Invalid many-to-many keys throws a helpful error message where one of a
- list of natural keys is invalid.
- """
- test_strings = [
- """{
- "pk": 1,
- "model": "serializers.categorymetadata",
- "fields": {"kind": "author","name": "meta1","value": "Agnes"}
- }""",
- """{
- "pk": 1,
- "model": "serializers.article",
- "fields": {
- "author": 1,
- "headline": "Unknown many to many",
- "pub_date": "2014-09-15T10:35:00",
- "meta_data": [
- ["author", "meta1"],
- ["doesnotexist", "meta1"],
- ["author", "meta1"]
- ]
- }
- }""",
- """{
- "pk": 1,
- "model": "serializers.author",
- "fields": {"name": "Agnes"}
- }"""
- ]
- test_string = "\n".join([s.replace("\n", "") for s in test_strings])
- key = ["doesnotexist", "meta1"]
- expected = "(serializers.article:pk=1) field_value was '%r'" % key
- with self.assertRaisesMessage(DeserializationError, expected):
- for obj in serializers.deserialize('jsonl', test_string):
- obj.save()
- def test_helpful_error_message_for_many2many_natural2(self):
- """
- Invalid many-to-many keys throws a helpful error message where a
- natural many-to-many key has only a single value.
- """
- test_strings = [
- """{
- "pk": 1,
- "model": "serializers.article",
- "fields": {
- "author": 1,
- "headline": "Unknown many to many",
- "pub_date": "2014-09-15T10:35:00",
- "meta_data": [1, "doesnotexist"]
- }
- }""",
- """{
- "pk": 1,
- "model": "serializers.categorymetadata",
- "fields": {"kind": "author","name": "meta1","value": "Agnes"}
- }""",
- """{
- "pk": 1,
- "model": "serializers.author",
- "fields": {"name": "Agnes"}
- }"""
- ]
- test_string = "\n".join([s.replace("\n", "") for s in test_strings])
- expected = "(serializers.article:pk=1) field_value was 'doesnotexist'"
- with self.assertRaisesMessage(DeserializationError, expected):
- for obj in serializers.deserialize('jsonl', test_string, ignore=False):
- obj.save()
- def test_helpful_error_message_for_many2many_not_iterable(self):
- """
- Not iterable many-to-many field value throws a helpful error message.
- """
- test_string = (
- '{"pk": 1,"model": "serializers.m2mdata","fields": {"data": null}}'
- )
- expected = "(serializers.m2mdata:pk=1) field_value was 'None'"
- with self.assertRaisesMessage(DeserializationError, expected):
- next(serializers.deserialize('jsonl', test_string, ignore=False))
- class JsonSerializerTransactionTestCase(SerializersTransactionTestBase, TransactionTestCase):
- serializer_name = "jsonl"
- fwd_ref_str = [
- """{
- "pk": 1,
- "model": "serializers.article",
- "fields": {
- "headline": "Forward references pose no problem",
- "pub_date": "2006-06-16T15:00:00",
- "categories": [1],
- "author": 1
- }
- }""",
- """{
- "pk": 1,
- "model": "serializers.category",
- "fields": {"name": "Reference"}
- }""",
- """{
- "pk": 1,
- "model": "serializers.author",
- "fields": {"name": "Agnes"}
- }"""
- ]
- fwd_ref_str = "\n".join([s.replace("\n", "") for s in fwd_ref_str])
|