<commit_before>"""
Custom model fields for Django.
"""
import types

from django.conf import settings
from django.db import models
from django.utils import simplejson

from kikola.forms import fields
from kikola.forms.widgets import JSONWidget


__all__ = ('JSONField', 'PickleField', 'URLField')


if getattr(settings, 'USE_CPICKLE', False):
    import cPickle as pickle
else:
    import pickle


class JSONField(models.TextField):
    """
    Model field that stores all Python object as JSON string.
    """
    __metaclass__ = models.SubfieldBase

    def contribute_to_class(self, cls, name):
        super(JSONField, self).contribute_to_class(cls, name)

        def get_json(model):
            return self.get_db_prep_value(getattr(model, self.attname))
        setattr(cls, 'get_%s_json' % self.name, get_json)

        def set_json(model, json):
            setattr(model, self.attname, self.to_python(json))
        setattr(cls, 'set_%s_json' % self.name, set_json)

    def formfield(self, **kwargs):
        kwargs['widget'] = JSONWidget(attrs={'class': 'vLargeTextField'})
        return super(JSONField, self).formfield(**kwargs)

    def get_db_prep_value(self, value):
        return simplejson.dumps(value)

    def to_python(self, value):
        if not isinstance(value, basestring):
            return value

        if value == '':
            return value

        try:
            return simplejson.loads(value, encoding=settings.DEFAULT_CHARSET)
        except ValueError, e:
            # If string could not parse as JSON it's means that it's Python
            # string saved to JSONField.
            return value


class PickleField(models.TextField):
    """
    Custom field that enables to store pickled Python objects.
    """
    __metaclass__ = models.SubfieldBase

    editable = False
    serialize = False

    def get_db_prep_value(self, value):
        # Make able to store Django model objects in ``PickleField``
        if hasattr(value, 'prepare_database_save') and \
           isinstance(getattr(value, 'prepare_database_save'),
                      types.LambdaType):
            delattr(value, 'prepare_database_save')

        return pickle.dumps(value)

    def get_default(self):
        if self.has_default():
            if callable(self.default):
                return self.default()
            return self.default
        return super(PickleField, self).get_default()

    def to_python(self, value):
        # Make able to store Django model objects in ``PickleField``
        if hasattr(value, 'prepare_database_save'):
            value.prepare_database_save = \
                lambda unused: PickleField().get_db_prep_value(value)

        if not isinstance(value, basestring):
            return value

        try:
            return pickle.loads(smart_str(value))
        except (EOFError, IndexError, KeyError, ValueError):
            # If pickle could not loads from string it's means that it's Python
            # string saved to PickleField.
            return value


class URLField(models.URLField):
    """
    Custom field that enables to store absolute URL, not only schemed value.
    """
    def formfield(self, **kwargs):
        defaults = {'form_class': fields.URLField,
                    'verify_exists': self.verify_exists}
        defaults.update(kwargs)
        return super(URLField, self).formfield(**defaults)<commit_msg>Fix storing Django model objects in ``PickleField``.<commit_after>"""
Custom model fields for Django.
"""
from django.conf import settings
from django.db import models
from django.utils import simplejson

from kikola.forms import fields
from kikola.forms.widgets import JSONWidget


__all__ = ('JSONField', 'PickleField', 'URLField')


if getattr(settings, 'USE_CPICKLE', False):
    import cPickle as pickle
else:
    import pickle


class JSONField(models.TextField):
    """
    Model field that stores all Python object as JSON string.
    """
    __metaclass__ = models.SubfieldBase

    def contribute_to_class(self, cls, name):
        super(JSONField, self).contribute_to_class(cls, name)

        def get_json(model):
            return self.get_db_prep_value(getattr(model, self.attname))
        setattr(cls, 'get_%s_json' % self.name, get_json)

        def set_json(model, json):
            setattr(model, self.attname, self.to_python(json))
        setattr(cls, 'set_%s_json' % self.name, set_json)

    def formfield(self, **kwargs):
        kwargs['widget'] = JSONWidget(attrs={'class': 'vLargeTextField'})
        return super(JSONField, self).formfield(**kwargs)

    def get_db_prep_value(self, value):
        return simplejson.dumps(value)

    def to_python(self, value):
        if not isinstance(value, basestring):
            return value

        if value == '':
            return value

        try:
            return simplejson.loads(value, encoding=settings.DEFAULT_CHARSET)
        except ValueError, e:
            # If string could not parse as JSON it's means that it's Python
            # string saved to JSONField.
            return value


class PickleField(models.TextField):
    """
    Custom field that enables to store pickled Python objects.
    """
    __metaclass__ = models.SubfieldBase

    editable = False
    serialize = False

    def get_db_prep_value(self, value):
        return pickle.dumps(value)

    def get_default(self):
        if self.has_default():
            if callable(self.default):
                return self.default()
            return self.default
        return super(PickleField, self).get_default()

    def to_python(self, value):
        if not isinstance(value, basestring):
            return value

        try:
            return pickle.loads(smart_str(value))
        except (EOFError, IndexError, KeyError, ValueError):
            # If pickle could not loads from string it's means that it's Python
            # string saved to PickleField.
            return value


class URLField(models.URLField):
    """
    Custom field that enables to store absolute URL, not only schemed value.
    """
    def formfield(self, **kwargs):
        defaults = {'form_class': fields.URLField,
                    'verify_exists': self.verify_exists}
        defaults.update(kwargs)
        return super(URLField, self).formfield(**defaults)


# Make able to store Django model objects in ``PickleField``
def picklefield_prepare_database_save(obj, field):
    if isinstance(field, PickleField):
        return field.get_db_prep_save(obj)
    return super(models.Model, obj).prepare_database_save(field)


models.Model.prepare_database_save = picklefield_prepare_database_save
{'fraction_non_alphanumeric': 0.09318727490996398, 'fraction_numerical': 0.0, 'mean_word_length': 2.7255449972051426, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4397435', 'n_tokens_mistral': 1924, 'n_tokens_neox': 1849, 'n_words': 521}