<commit_before># -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.template.exceptions import TemplateDoesNotExist
from django.template.loader import get_template
from django.utils.html import format_html_join
from django.utils.safestring import mark_safe

from classytags.utils import flatten_context
from cms.utils import get_language_from_request
from djangocms_text_ckeditor.utils import OBJ_ADMIN_RE
from .mixins import CascadePluginMixin

__all__ = ['register_minion', 'MinionContentRenderer']

class EmulateQuerySet(object):
    def __init__(self, elements):
        self.elements = elements

    def all(self):
        for id, glossary in enumerate(self.elements, 1):
            yield type(str('MinionInlineElement'), (object,), {'id': id, 'glossary': glossary})()


class MinionElementBase(object):
    """
    Emulate a CascadeElement to be used by the CascadeContentRenderer instead of the CMSContentRenderer.
    """
    def __init__(self, plugin, data, children_data, parent=None):
        self.plugin = plugin
        self.pk = data.get('pk')
        self.glossary = data.get('glossary', {})
        self.sortinline_elements = self.inline_elements = EmulateQuerySet(data.get('inlines', []))
        self.children_data = children_data
        self.parent = parent

    @property
    def plugin_class(self):
        return self.plugin.__class__

    def child_plugin_instances(self):
        for plugin_type, data, children_data in self.children_data:
            plugin_class = minion_plugin_map.get(plugin_type)
            element_class = minion_element_map.get(plugin_type)
            if element_class:
                yield element_class(plugin_class(), data, children_data, parent=self)

    def get_num_children(self):
        return len(self.children_data)

    def get_complete_glossary(self):
        if not hasattr(self, '_complete_glossary_cache'):
            self._complete_glossary_cache = self.get_parent_glossary().copy()
            self._complete_glossary_cache.update(self.glossary or {})
        return self._complete_glossary_cache

    def get_parent_glossary(self):
        if self.parent:
            return self.parent.get_complete_glossary()
        return {}
        # TODO: use self.placeholder.glossary as the starting dictionary
        template = self.placeholder.page.template if self.placeholder.page else None
        return get_placeholder_conf('glossary', self.placeholder.slot, template=template, default={})

    @property
    def tag_type(self):
        return self.plugin_class.get_tag_type(self)

    @property
    def css_classes(self):
        css_classes = self.plugin_class.get_css_classes(self)
        return mark_safe(' '.join(c for c in css_classes if c))

    @property
    def inline_styles(self):
        inline_styles = self.plugin_class.get_inline_styles(self)
        return format_html_join(' ', '{0}: {1};', (s for s in inline_styles.items() if s[1]))

    @property
    def html_tag_attributes(self):
        attributes = self.plugin_class.get_html_tag_attributes(self)
        return format_html_join(' ', '{0}="{1}"', ((attr, val) for attr, val in attributes.items() if val))


class TextMinionElement(object):
    def __init__(self, plugin, data, children_data, parent=None):
        self.plugin = plugin
        self.pk = data.get('pk')
        self.body = data.get('body')
        self.children_data = children_data
        self.parent = parent

    def tags_to_user_html(self, context, placeholder):
        content_renderer = context['cms_content_renderer']
        children_instances = {}
        for plugin_type, data, children_data in self.children_data:
            plugin_class = minion_plugin_map.get(plugin_type)
            element_class = minion_element_map.get(plugin_type)
            if element_class and 'pk' in data:
                sub_plugin = plugin_class()
                children_instances[data['pk']] = element_class(sub_plugin, data, children_data, parent=self)

        def _render_tag(m):
            plugin_id = int(m.groupdict()['pk'])
            instance = children_instances[plugin_id]
            with context.push():
                sub_context = instance.plugin.render(context, instance, placeholder)
                return content_renderer.render_plugin(instance, sub_context)

        return OBJ_ADMIN_RE.sub(_render_tag, self.body)


class MinionPluginBase(CascadePluginMixin):
    """
    Whenever djangocms-cascade is used in readonly mode, all Cascade plugins are instantiated a second time
    where class CascadePluginBase is replaced against this class in order to remove its dependency to django-CMS.
    """

    def __init__(self, model=None, admin_site=None, glossary_fields=None):
        if isinstance(glossary_fields, (list, tuple)):
            self.glossary_fields = list(glossary_fields)
        elif not hasattr(self, 'glossary_fields'):
            self.glossary_fields = []

    @classmethod
    def super(cls, klass, instance):
        return super(minion_plugin_map[klass.__name__], instance)

    def render(self, context, instance, placeholder):
        context.update({
            'instance': instance,
        })
        return context

    def _get_render_template(self, context, instance, placeholder):
        if hasattr(self, 'get_render_template'):
            template = self.get_render_template(context, instance, placeholder)
        elif getattr(self, 'render_template', False):
            template = getattr(self, 'render_template', False)
        else:
            template = None

        if not template:
            raise TemplateDoesNotExist("plugin {} has no render_template".format(self.__class__))
        return template

    def in_edit_mode(self, request, placeholder):
        return False

    def get_previous_instance(self, obj):
        if obj and obj.parent:
            for pos, sibling in enumerate(obj.parent.children_data):
                if sibling[1].get('pk') == obj.pk and pos > 0:
                    prev_pt, prev_data, prev_cd = obj.parent.children_data[pos - 1]
                    plugin = minion_plugin_map[prev_pt]()
                    element_class = minion_element_map.get(prev_pt)
                    return element_class(plugin, prev_data, prev_cd, parent=obj.parent), plugin
        return None, None

    def get_next_instance(self, obj):
        if obj and obj.parent:
            for pos, sibling in enumerate(obj.parent.children_data):
                if sibling[1].get('pk') == obj.pk and pos < len(obj.parent.children_data):
                    next_pt, next_data, next_cd = obj.parent.children_data[pos + 1]
                    plugin = minion_plugin_map[next_pt]()
                    element_class = minion_element_map.get(next_pt)
                    return element_class(plugin, next_data, next_cd, parent=obj.parent), plugin
        return None, None


class TextMinionPlugin(MinionPluginBase):
    render_template = 'cms/plugins/text.html'

    def render(self, context, instance, placeholder):
        context.update({
            'body': instance.tags_to_user_html(context, placeholder),
        })
        return context


class MinionContentRenderer(object):
    def __init__(self, request):
        self.request = request
        self.language = get_language_from_request(request)
        self._cached_templates = {}

    def render_tree(self, context, tree_data):
        content = []
        for plugin_type, data, children_data in tree_data['plugins']:
            plugin_class = minion_plugin_map.get(plugin_type)
            element_class = minion_element_map.get(plugin_type)
            plugin_instance = element_class(plugin_class(), data, children_data)
            content.append(self.render_plugin(plugin_instance, context))
        return mark_safe(''.join(content))

    def render_plugin(self, instance, context, placeholder=None, editable=False):
        # context = PluginContext(context, instance, placeholder)
        context = instance.plugin.render(context, instance, placeholder)
        context = flatten_context(context)

        template = instance.plugin._get_render_template(context, instance, placeholder)
        template = self.get_cached_template(template)
        content = template.render(context)<commit_msg>emulate pk for minion elements<commit_after># -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.template.exceptions import TemplateDoesNotExist
from django.template.loader import get_template
from django.utils.html import format_html_join
from django.utils.safestring import mark_safe

from classytags.utils import flatten_context
from cms.utils import get_language_from_request
from djangocms_text_ckeditor.utils import OBJ_ADMIN_RE
from .mixins import CascadePluginMixin

__all__ = ['register_minion', 'MinionContentRenderer']

class EmulateQuerySet(object):
    def __init__(self, elements):
        self.elements = elements

    def all(self):
        for id, glossary in enumerate(self.elements, 1):
            yield type(str('MinionInlineElement'), (object,), {'id': id, 'glossary': glossary})()


class MinionElementBase(object):
    """
    Emulate a CascadeElement to be used by the CascadeContentRenderer instead of the CMSContentRenderer.
    """
    def __init__(self, plugin, data, children_data, parent=None):
        self.plugin = plugin
        self.id = data.get('pk')
        self.glossary = data.get('glossary', {})
        self.sortinline_elements = self.inline_elements = EmulateQuerySet(data.get('inlines', []))
        self.children_data = children_data
        self.parent = parent

    @property
    def pk(self):
        return self.id

    @property
    def plugin_class(self):
        return self.plugin.__class__

    def child_plugin_instances(self):
        for plugin_type, data, children_data in self.children_data:
            plugin_class = minion_plugin_map.get(plugin_type)
            element_class = minion_element_map.get(plugin_type)
            if element_class:
                yield element_class(plugin_class(), data, children_data, parent=self)

    def get_num_children(self):
        return len(self.children_data)

    def get_complete_glossary(self):
        if not hasattr(self, '_complete_glossary_cache'):
            self._complete_glossary_cache = self.get_parent_glossary().copy()
            self._complete_glossary_cache.update(self.glossary or {})
        return self._complete_glossary_cache

    def get_parent_glossary(self):
        if self.parent:
            return self.parent.get_complete_glossary()
        return {}
        # TODO: use self.placeholder.glossary as the starting dictionary
        template = self.placeholder.page.template if self.placeholder.page else None
        return get_placeholder_conf('glossary', self.placeholder.slot, template=template, default={})

    @property
    def tag_type(self):
        return self.plugin_class.get_tag_type(self)

    @property
    def css_classes(self):
        css_classes = self.plugin_class.get_css_classes(self)
        return mark_safe(' '.join(c for c in css_classes if c))

    @property
    def inline_styles(self):
        inline_styles = self.plugin_class.get_inline_styles(self)
        return format_html_join(' ', '{0}: {1};', (s for s in inline_styles.items() if s[1]))

    @property
    def html_tag_attributes(self):
        attributes = self.plugin_class.get_html_tag_attributes(self)
        return format_html_join(' ', '{0}="{1}"', ((attr, val) for attr, val in attributes.items() if val))


class TextMinionElement(object):
    def __init__(self, plugin, data, children_data, parent=None):
        self.plugin = plugin
        self.pk = data.get('pk')
        self.body = data.get('body')
        self.children_data = children_data
        self.parent = parent

    def tags_to_user_html(self, context, placeholder):
        content_renderer = context['cms_content_renderer']
        children_instances = {}
        for plugin_type, data, children_data in self.children_data:
            plugin_class = minion_plugin_map.get(plugin_type)
            element_class = minion_element_map.get(plugin_type)
            if element_class and 'pk' in data:
                sub_plugin = plugin_class()
                children_instances[data['pk']] = element_class(sub_plugin, data, children_data, parent=self)

        def _render_tag(m):
            plugin_id = int(m.groupdict()['pk'])
            instance = children_instances[plugin_id]
            with context.push():
                sub_context = instance.plugin.render(context, instance, placeholder)
                return content_renderer.render_plugin(instance, sub_context)

        return OBJ_ADMIN_RE.sub(_render_tag, self.body)


class MinionPluginBase(CascadePluginMixin):
    """
    Whenever djangocms-cascade is used in readonly mode, all Cascade plugins are instantiated a second time
    where class CascadePluginBase is replaced against this class in order to remove its dependency to django-CMS.
    """

    def __init__(self, model=None, admin_site=None, glossary_fields=None):
        if isinstance(glossary_fields, (list, tuple)):
            self.glossary_fields = list(glossary_fields)
        elif not hasattr(self, 'glossary_fields'):
            self.glossary_fields = []

    @classmethod
    def super(cls, klass, instance):
        return super(minion_plugin_map[klass.__name__], instance)

    def render(self, context, instance, placeholder):
        context.update({
            'instance': instance,
        })
        return context

    def _get_render_template(self, context, instance, placeholder):
        if hasattr(self, 'get_render_template'):
            template = self.get_render_template(context, instance, placeholder)
        elif getattr(self, 'render_template', False):
            template = getattr(self, 'render_template', False)
        else:
            template = None

        if not template:
            raise TemplateDoesNotExist("plugin {} has no render_template".format(self.__class__))
        return template

    def in_edit_mode(self, request, placeholder):
        return False

    def get_previous_instance(self, obj):
        if obj and obj.parent:
            for pos, sibling in enumerate(obj.parent.children_data):
                if sibling[1].get('pk') == obj.pk and pos > 0:
                    prev_pt, prev_data, prev_cd = obj.parent.children_data[pos - 1]
                    plugin = minion_plugin_map[prev_pt]()
                    element_class = minion_element_map.get(prev_pt)
                    return element_class(plugin, prev_data, prev_cd, parent=obj.parent), plugin
        return None, None

    def get_next_instance(self, obj):
        if obj and obj.parent:
            for pos, sibling in enumerate(obj.parent.children_data):
                if sibling[1].get('pk') == obj.pk and pos < len(obj.parent.children_data):
                    next_pt, next_data, next_cd = obj.parent.children_data[pos + 1]
                    plugin = minion_plugin_map[next_pt]()
                    element_class = minion_element_map.get(next_pt)
                    return element_class(plugin, next_data, next_cd, parent=obj.parent), plugin
        return None, None


class TextMinionPlugin(MinionPluginBase):
    render_template = 'cms/plugins/text.html'

    def render(self, context, instance, placeholder):
        context.update({
            'body': instance.tags_to_user_html(context, placeholder),
        })
        return context


class MinionContentRenderer(object):
    def __init__(self, request):
        self.request = request
        self.language = get_language_from_request(request)
        self._cached_templates = {}

    def render_tree(self, context, tree_data):
        content = []
        for plugin_type, data, children_data in tree_data['plugins']:
            plugin_class = minion_plugin_map.get(plugin_type)
            element_class = minion_element_map.get(plugin_type)
            plugin_instance = element_class(plugin_class(), data, children_data)
            content.append(self.render_plugin(plugin_instance, context))
        return mark_safe(''.join(content))

    def render_plugin(self, instance, context, placeholder=None, editable=False):
        context = instance.plugin.render(context, instance, placeholder)
        context = flatten_context(context)

        template = instance.plugin._get_render_template(context, instance, placeholder)
        template = self.get_cached_template(template)
        content = template.render(context)
{'fraction_non_alphanumeric': 0.09331400616053633, 'fraction_numerical': 0.0014495379597753216, 'mean_word_length': 2.9975857073877354, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, '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': '7030587', 'n_tokens_mistral': 4736, 'n_tokens_neox': 4618, 'n_words': 1066}