Source code for contentful.content_type_field_types

# -*- coding: utf-8 -*-

try:
    import simplejson as json
except ImportError:
    import json

import dateutil.parser
from collections import namedtuple
from .utils import unicode_class, resource_for_link, unresolvable
from .resource import FieldsResource, Link, Resource

"""
contentful.content_type_field_types
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

This module implements the Field Coercion classes.

:copyright: (c) 2016 by Contentful GmbH.
:license: MIT, see LICENSE for more details.
"""


[docs]class BasicField(object): """Base Coercion Class""" def __init__(self, items=None): self._items = items
[docs] def coerce(self, value, **kwargs): """Just returns the value.""" return value
def __repr__(self): return "<{0}>".format( self.__class__.__name__ )
[docs]class SymbolField(BasicField): """Symbol Coercion Class"""
[docs] def coerce(self, value, **kwargs): """Coerces value to str""" return unicode_class()(value)
[docs]class TextField(BasicField): """Text Coercion Class"""
[docs] def coerce(self, value, **kwargs): """Coerces value to str""" return unicode_class()(value)
[docs]class IntegerField(BasicField): """Integer Coercion Class"""
[docs] def coerce(self, value, **kwargs): """Coerces value to int""" return int(value)
[docs]class NumberField(BasicField): """Number Coercion Class"""
[docs] def coerce(self, value, **kwargs): """Coerces value to float""" return float(value)
[docs]class DateField(BasicField): """Date Coercion Class"""
[docs] def coerce(self, value, **kwargs): """Coerces ISO8601 date to :class:`datetime.datetime` object.""" return dateutil.parser.parse(value)
[docs]class BooleanField(BasicField): """Boolean Coercion Class"""
[docs] def coerce(self, value, **kwargs): """Coerces value to boolean""" return bool(value)
[docs]class LocationField(BasicField): """Location Coercion Class"""
[docs] def coerce(self, value, **kwargs): """Coerces value to Location object""" Location = namedtuple('Location', ['lat', 'lon']) return Location(float(value.get('lat')), float(value.get('lon')))
[docs]class LinkField(BasicField): """ LinkField Nothing should be done here as include resolution is handled within entries due to depth handling (explained within Entry). Only present as a placeholder for proper resolution within ContentType. """ pass
[docs]class ResourceLinkField(BasicField): """ ResourceLinkField Nothing should be done here as ResourceLink does not support entity resolution on the backend side and linked field can’t be used in ordering and filtering queries. """ pass
[docs]class ArrayField(BasicField): """Array Coercion Class Coerces items in collection with it's proper Coercion Class. """ def __init__(self, items=None): super(ArrayField, self).__init__(items) self._coercion = self._get_coercion()
[docs] def coerce(self, value, **kwargs): """Coerces array items with proper coercion.""" result = [] for v in value: result.append(self._coercion.coerce(v, **kwargs)) return result
def _get_coercion(self): return globals()["{0}Field".format(self._items.get('type'))]()
[docs]class ObjectField(BasicField): """ Object Coercion Class. """
[docs] def coerce(self, value, **kwargs): """Coerces JSON values properly.""" return json.loads(json.dumps(value))
[docs]class RichTextField(BasicField): """ Coerces Rich Text fields and resolves includes for entries included. """ def _coerce_link(self, value, includes=None, errors=None, resources=None, default_locale='en-US', locale=None): if value['data']['target']['sys']['type'] != 'Link': return value['data']['target'] if unresolvable(value['data']['target'], errors): return None resource = resource_for_link( value['data']['target'], includes, resources, locale=locale if locale else '*' ) if isinstance(resource, FieldsResource): # Resource comes from instance cache return resource if resource is None: # Resource is valid but not reachable on includes return Link(value['data']['target']) from .resource_builder import ResourceBuilder return ResourceBuilder( default_locale, locale and locale == '*', resource, includes_for_single=includes, errors_for_single=errors, reuse_entries=bool(resources), resources=resources ).build() def _coerce_block(self, value, includes=None, errors=None, resources=None, default_locale='en-US', locale=None): if not (isinstance(value, dict) and 'content' in value): return value invalid_nodes = [] coerced_nodes = {} for index, node in enumerate(value['content']): if node.get('data', None) and node['data'].get('target', None): # Resource has already been hydrated previously if isinstance(node['data']['target'], Resource): continue link = self._coerce_link( node, includes=includes, errors=errors, resources=resources, default_locale=default_locale, locale=locale ) if link: node['data']['target'] = link else: invalid_nodes.append(index) if node.get('content', None): coerced_nodes[index] = self._coerce_block( node, includes=includes, errors=errors, resources=resources, default_locale=default_locale, locale=locale ) for node_index, coerced_node in coerced_nodes.items(): value['content'][node_index] = coerced_node for node_index in reversed(invalid_nodes): del value['content'][node_index] return value
[docs] def coerce(self, value, includes=None, errors=None, resources=None, default_locale='en-US', locale=None): """Coerces Rich Text properly.""" if includes is None: includes = [] if errors is None: errors = [] return self._coerce_block( value, includes=includes, errors=errors, resources=resources, default_locale=default_locale, locale=locale )