<commit_before># -*- coding: utf-8 -*-
""" QuerySet for PolymorphicModel
    Please see README.rst or DOCS.rst or http://chrisglass.github.com/django_polymorphic/
"""
from __future__ import absolute_import

import copy
from collections import defaultdict

import django
from django.db.models.query import QuerySet, Q
from django.contrib.contenttypes.models import ContentType
from django.utils import six

from .query_translate import translate_polymorphic_filter_definitions_in_kwargs, translate_polymorphic_filter_definitions_in_args
from .query_translate import translate_polymorphic_field_path, translate_polymorphic_Q_object

# chunk-size: maximum number of objects requested per db-request
# by the polymorphic queryset.iterator() implementation; we use the same chunk size as Django
try:
    from django.db.models.query import CHUNK_SIZE               # this is 100 for Django 1.1/1.2
except ImportError:
    # CHUNK_SIZE was removed in Django 1.6
    CHUNK_SIZE = 100
Polymorphic_QuerySet_objects_per_request = CHUNK_SIZE


def transmogrify(cls, obj):
    """
    Upcast a class to a different type without asking questions.
    """
    if not '__init__' in obj.__dict__:
        # Just assign __class__ to a different value.
        new = obj
        new.__class__ = cls
    else:
        # Run constructor, reassign values
        new = cls()
        for k, v in obj.__dict__.items():
            new.__dict__[k] = v
    return new


###################################################################################
# PolymorphicQuerySet

def _query_annotations(query):
    try:
        return query.annotations
    except AttributeError:
        # Django < 1.8
        return query.aggregates


class PolymorphicQuerySet(QuerySet):
    """
    QuerySet for PolymorphicModel

    Contains the core functionality for PolymorphicModel

    Usually not explicitly needed, except if a custom queryset class
    is to be used.
    """

    def __init__(self, *args, **kwargs):
        "init our queryset object member variables"
        self.polymorphic_disabled = False
        # A parallel structure to django.db.models.query.Query.deferred_loading,
        # which we maintain with the untranslated field names passed to
        # .defer() and .only() in order to be able to retranslate them when
        # retrieving the real instance (so that the deferred fields apply
        # to that queryset as well).
        self.polymorphic_deferred_loading = (set([]), True)
        super(PolymorphicQuerySet, self).__init__(*args, **kwargs)

    def _clone(self, *args, **kwargs):
        "Django's _clone only copies its own variables, so we need to copy ours here"
        new = super(PolymorphicQuerySet, self)._clone(*args, **kwargs)
        new.polymorphic_disabled = self.polymorphic_disabled
        new.polymorphic_deferred_loading = (
            copy.copy(self.polymorphic_deferred_loading[0]),
            self.polymorphic_deferred_loading[1])
        return new

    if django.VERSION >= (1, 7):
        def as_manager(cls):
            # Make sure the Django 1.7 way of creating managers works.
            from .managers import PolymorphicManager
            manager = PolymorphicManager.from_queryset(cls)()
            manager._built_with_as_manager = True
            return manager
        as_manager.queryset_only = True
        as_manager = classmethod(as_manager)

    def non_polymorphic(self):
        """switch off polymorphic behaviour for this query.
        When the queryset is evaluated, only objects of the type of the
        base class used for this query are returned."""
        qs = self._clone()
        qs.polymorphic_disabled = True
        return qs

    def instance_of(self, *args):
        """Filter the queryset to only include the classes in args (and their subclasses).
        Implementation in _translate_polymorphic_filter_defnition."""
        return self.filter(instance_of=args)

    def not_instance_of(self, *args):
        """Filter the queryset to exclude the classes in args (and their subclasses).
        Implementation in _translate_polymorphic_filter_defnition."""
        return self.filter(not_instance_of=args)

    def _filter_or_exclude(self, negate, *args, **kwargs):
        "We override this internal Django functon as it is used for all filter member functions."
        translate_polymorphic_filter_definitions_in_args(self.model, args)  # the Q objects
        additional_args = translate_polymorphic_filter_definitions_in_kwargs(self.model, kwargs)  # filter_field='data'
        return super(PolymorphicQuerySet, self)._filter_or_exclude(negate, *(list(args) + additional_args), **kwargs)

    def order_by(self, *args, **kwargs):
        """translate the field paths in the args, then call vanilla order_by."""
        new_args = [translate_polymorphic_field_path(self.model, a) for a in args]
        return super(PolymorphicQuerySet, self).order_by(*new_args, **kwargs)

    def defer(self, *fields):
        """
        Translate the field paths in the args, then call vanilla defer.

        Also retain a copy of the original fields passed, which we'll need
        when we're retrieving the real instance (since we'll need to translate
        them again, as the model will have changed).
        """
        new_fields = [translate_polymorphic_field_path(self.model, a) for a in fields]
        clone = super(PolymorphicQuerySet, self).defer(*new_fields)
        clone._polymorphic_add_deferred_loading(fields)
        return clone

    def only(self, *fields):
        """
        Translate the field paths in the args, then call vanilla only.

        Also retain a copy of the original fields passed, which we'll need
        when we're retrieving the real instance (since we'll need to translate
        them again, as the model will have changed).
        """
        new_fields = [translate_polymorphic_field_path(self.model, a) for a in fields]
        clone = super(PolymorphicQuerySet, self).only(*new_fields)
        clone._polymorphic_add_immediate_loading(fields)
        return clone

    def _polymorphic_add_deferred_loading(self, field_names):
        """
        Follows the logic of django.db.models.query.Query.add_deferred_loading(),
        but for the non-translated field names that were passed to self.defer().
        """
        existing, defer = self.polymorphic_deferred_loading
        if defer:
            # Add to existing deferred names.
            self.polymorphic_deferred_loading = existing.union(field_names), True
        else:
            # Remove names from the set of any existing "immediate load" names.
            self.polymorphic_deferred_loading = existing.difference(field_names), False

    def _polymorphic_add_immediate_loading(self, field_names):
        """
        Follows the logic of django.db.models.query.Query.add_immediate_loading(),
        but for the non-translated field names that were passed to self.only()
        """
        existing, defer = self.polymorphic_deferred_loading
        field_names = set(field_names)
        if 'pk' in field_names:
            field_names.remove('pk')
            field_names.add(self.model._meta.pk.name)

        if defer:
            # Remove any existing deferred names from the current set before
            # setting the new names.
            self.polymorphic_deferred_loading = field_names.difference(existing), False
        else:
            # Replace any existing "immediate load" field names.
            self.polymorphic_deferred_loading = field_names, False

    def _process_aggregate_args(self, args, kwargs):
        """for aggregate and annotate kwargs: allow ModelX___field syntax for kwargs, forbid it for args.
        Modifies kwargs if needed (these are Aggregate objects, we translate the lookup member variable)"""

        def patch_lookup_lt_18(a):
            a.lookup = translate_polymorphic_field_path(self.model, a.lookup)


        def patch_lookup_gte_18(a):
            # With Django > 1.8, the field on which the aggregate operates is
            # stored inside a complex query expression.
            if isinstance(a, Q):
                translate_polymorphic_Q_object(self.model, a)
            elif hasattr(a, 'get_source_expressions'):
                for source_expression in a.get_source_expressions():
                    patch_lookup_gte_18(source_expression)
            else:
                a.name = translate_polymorphic_field_path(self.model, a.name)

        ___lookup_assert_msg = 'PolymorphicModel: annotate()/aggregate(): ___ model lookup supported for keyword arguments only'
        def test___lookup_for_args_lt_18(a):
            assert '___' not in a.lookup, ___lookup_assert_msg

        def test___lookup_for_args_gte_18(a):
            """ *args might be complex expressions too in django 1.8 so
            the testing for a '___' is rather complex on this one """
            if isinstance(a, Q):
                def tree_node_test___lookup(my_model, node):
                    " process all children of this Q node "
                    for i in range(len(node.children)):
                        child = node.children[i]

                        if type(child) == tuple:
                            # this Q object child is a tuple => a kwarg like Q( instance_of=ModelB )
                            assert '___' not in child[0], ___lookup_assert_msg
                        else:
                            # this Q object child is another Q object, recursively process this as well
                            tree_node_test___lookup(my_model, child)

                tree_node_test___lookup(self.model, a)
            elif hasattr(a, 'get_source_expressions'):
                for source_expression in a.get_source_expressions():
                    test___lookup_for_args_gte_18(source_expression)
            else:<commit_msg>Fix error when using `date_hierarchy` field in the admin<commit_after># -*- coding: utf-8 -*-
""" QuerySet for PolymorphicModel
    Please see README.rst or DOCS.rst or http://chrisglass.github.com/django_polymorphic/
"""
from __future__ import absolute_import

import copy
from collections import defaultdict

import django
from django.db.models.query import QuerySet, Q
from django.contrib.contenttypes.models import ContentType
from django.utils import six

from .query_translate import translate_polymorphic_filter_definitions_in_kwargs, translate_polymorphic_filter_definitions_in_args
from .query_translate import translate_polymorphic_field_path, translate_polymorphic_Q_object

# chunk-size: maximum number of objects requested per db-request
# by the polymorphic queryset.iterator() implementation; we use the same chunk size as Django
try:
    from django.db.models.query import CHUNK_SIZE               # this is 100 for Django 1.1/1.2
except ImportError:
    # CHUNK_SIZE was removed in Django 1.6
    CHUNK_SIZE = 100
Polymorphic_QuerySet_objects_per_request = CHUNK_SIZE


def transmogrify(cls, obj):
    """
    Upcast a class to a different type without asking questions.
    """
    if not '__init__' in obj.__dict__:
        # Just assign __class__ to a different value.
        new = obj
        new.__class__ = cls
    else:
        # Run constructor, reassign values
        new = cls()
        for k, v in obj.__dict__.items():
            new.__dict__[k] = v
    return new


###################################################################################
# PolymorphicQuerySet

def _query_annotations(query):
    try:
        return query.annotations
    except AttributeError:
        # Django < 1.8
        return query.aggregates


class PolymorphicQuerySet(QuerySet):
    """
    QuerySet for PolymorphicModel

    Contains the core functionality for PolymorphicModel

    Usually not explicitly needed, except if a custom queryset class
    is to be used.
    """

    def __init__(self, *args, **kwargs):
        "init our queryset object member variables"
        self.polymorphic_disabled = False
        # A parallel structure to django.db.models.query.Query.deferred_loading,
        # which we maintain with the untranslated field names passed to
        # .defer() and .only() in order to be able to retranslate them when
        # retrieving the real instance (so that the deferred fields apply
        # to that queryset as well).
        self.polymorphic_deferred_loading = (set([]), True)
        super(PolymorphicQuerySet, self).__init__(*args, **kwargs)

    def _clone(self, *args, **kwargs):
        "Django's _clone only copies its own variables, so we need to copy ours here"
        new = super(PolymorphicQuerySet, self)._clone(*args, **kwargs)
        new.polymorphic_disabled = self.polymorphic_disabled
        new.polymorphic_deferred_loading = (
            copy.copy(self.polymorphic_deferred_loading[0]),
            self.polymorphic_deferred_loading[1])
        return new

    if django.VERSION >= (1, 7):
        def as_manager(cls):
            # Make sure the Django 1.7 way of creating managers works.
            from .managers import PolymorphicManager
            manager = PolymorphicManager.from_queryset(cls)()
            manager._built_with_as_manager = True
            return manager
        as_manager.queryset_only = True
        as_manager = classmethod(as_manager)

    def non_polymorphic(self):
        """switch off polymorphic behaviour for this query.
        When the queryset is evaluated, only objects of the type of the
        base class used for this query are returned."""
        qs = self._clone()
        qs.polymorphic_disabled = True
        return qs

    def instance_of(self, *args):
        """Filter the queryset to only include the classes in args (and their subclasses).
        Implementation in _translate_polymorphic_filter_defnition."""
        return self.filter(instance_of=args)

    def not_instance_of(self, *args):
        """Filter the queryset to exclude the classes in args (and their subclasses).
        Implementation in _translate_polymorphic_filter_defnition."""
        return self.filter(not_instance_of=args)

    def _filter_or_exclude(self, negate, *args, **kwargs):
        "We override this internal Django functon as it is used for all filter member functions."
        translate_polymorphic_filter_definitions_in_args(self.model, args)  # the Q objects
        additional_args = translate_polymorphic_filter_definitions_in_kwargs(self.model, kwargs)  # filter_field='data'
        return super(PolymorphicQuerySet, self)._filter_or_exclude(negate, *(list(args) + additional_args), **kwargs)

    def order_by(self, *args, **kwargs):
        """translate the field paths in the args, then call vanilla order_by."""
        new_args = [translate_polymorphic_field_path(self.model, a) for a in args]
        return super(PolymorphicQuerySet, self).order_by(*new_args, **kwargs)

    def defer(self, *fields):
        """
        Translate the field paths in the args, then call vanilla defer.

        Also retain a copy of the original fields passed, which we'll need
        when we're retrieving the real instance (since we'll need to translate
        them again, as the model will have changed).
        """
        new_fields = [translate_polymorphic_field_path(self.model, a) for a in fields]
        clone = super(PolymorphicQuerySet, self).defer(*new_fields)
        clone._polymorphic_add_deferred_loading(fields)
        return clone

    def only(self, *fields):
        """
        Translate the field paths in the args, then call vanilla only.

        Also retain a copy of the original fields passed, which we'll need
        when we're retrieving the real instance (since we'll need to translate
        them again, as the model will have changed).
        """
        new_fields = [translate_polymorphic_field_path(self.model, a) for a in fields]
        clone = super(PolymorphicQuerySet, self).only(*new_fields)
        clone._polymorphic_add_immediate_loading(fields)
        return clone

    def _polymorphic_add_deferred_loading(self, field_names):
        """
        Follows the logic of django.db.models.query.Query.add_deferred_loading(),
        but for the non-translated field names that were passed to self.defer().
        """
        existing, defer = self.polymorphic_deferred_loading
        if defer:
            # Add to existing deferred names.
            self.polymorphic_deferred_loading = existing.union(field_names), True
        else:
            # Remove names from the set of any existing "immediate load" names.
            self.polymorphic_deferred_loading = existing.difference(field_names), False

    def _polymorphic_add_immediate_loading(self, field_names):
        """
        Follows the logic of django.db.models.query.Query.add_immediate_loading(),
        but for the non-translated field names that were passed to self.only()
        """
        existing, defer = self.polymorphic_deferred_loading
        field_names = set(field_names)
        if 'pk' in field_names:
            field_names.remove('pk')
            field_names.add(self.model._meta.pk.name)

        if defer:
            # Remove any existing deferred names from the current set before
            # setting the new names.
            self.polymorphic_deferred_loading = field_names.difference(existing), False
        else:
            # Replace any existing "immediate load" field names.
            self.polymorphic_deferred_loading = field_names, False

    def _process_aggregate_args(self, args, kwargs):
        """for aggregate and annotate kwargs: allow ModelX___field syntax for kwargs, forbid it for args.
        Modifies kwargs if needed (these are Aggregate objects, we translate the lookup member variable)"""

        def patch_lookup_lt_18(a):
            a.lookup = translate_polymorphic_field_path(self.model, a.lookup)


        def patch_lookup_gte_18(a):
            # With Django > 1.8, the field on which the aggregate operates is
            # stored inside a complex query expression.
            if isinstance(a, Q):
                translate_polymorphic_Q_object(self.model, a)
            elif hasattr(a, 'get_source_expressions'):
                for source_expression in a.get_source_expressions():
                    if source_expression is not None:
                        patch_lookup_gte_18(source_expression)
            else:
                a.name = translate_polymorphic_field_path(self.model, a.name)

        ___lookup_assert_msg = 'PolymorphicModel: annotate()/aggregate(): ___ model lookup supported for keyword arguments only'
        def test___lookup_for_args_lt_18(a):
            assert '___' not in a.lookup, ___lookup_assert_msg

        def test___lookup_for_args_gte_18(a):
            """ *args might be complex expressions too in django 1.8 so
            the testing for a '___' is rather complex on this one """
            if isinstance(a, Q):
                def tree_node_test___lookup(my_model, node):
                    " process all children of this Q node "
                    for i in range(len(node.children)):
                        child = node.children[i]

                        if type(child) == tuple:
                            # this Q object child is a tuple => a kwarg like Q( instance_of=ModelB )
                            assert '___' not in child[0], ___lookup_assert_msg
                        else:
                            # this Q object child is another Q object, recursively process this as well
                            tree_node_test___lookup(my_model, child)

                tree_node_test___lookup(self.model, a)
            elif hasattr(a, 'get_source_expressions'):
                for source_expression in a.get_source_expressions():
                    test___lookup_for_args_gte_18(source_expression)
            else:
{'fraction_non_alphanumeric': 0.07957119130303487, 'fraction_numerical': 0.0038250541043837135, 'mean_word_length': 2.6796296296296296, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 9, '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': '5355106', 'n_tokens_mistral': 5562, 'n_tokens_neox': 5252, 'n_words': 1674}