<commit_before>import re

from django import template
from django.core.urlresolvers import reverse
from django.template.base import Node, TemplateSyntaxError
from django.utils.module_loading import import_by_path

from ..base import Flow
from ..compat import get_app_package


kwarg_re = re.compile(r"(\w+)=?(.+)")
register = template.Library()


class FlowURLNode(Node):
    def __init__(self, flow_ref, url_name, kwargs):
        self.flow_ref = flow_ref
        self.url_name = url_name
        self.kwargs = kwargs

    def render(self, context):
        # resolve flow reference
        flow_path = self.flow_ref.resolve(context)

        if isinstance(flow_path, Flow):
            flow_cls = flow_path
        else:
            try:
                app_label, flow_cls_path = flow_path.split('/')
            except ValueError:
                raise TemplateSyntaxError("Flow action should looks like app_label/FlowCls")

            app_package = get_app_package(app_label)
            if app_package is None:
                raise TemplateSyntaxError("{} app not found".format(app_label))

            flow_cls = import_by_path('{}.flows.{}'.format(app_package, flow_cls_path))

        # resolve url name and args
        url = self.url_name.resolve(context)
        kwargs = {key: value.resolve(context) for key, value in self.kwargs.items()}

        return reverse(url, current_app=flow_cls._meta.namespace, kwargs=kwargs)


@register.tag
def flowurl(parser, token):
    """
    Bound to flow {% url %} tag.

    Accepts flow namespace or flow class as first argument,
    and rest same as url tag Returns an absolute URL matching
    given flow action

    Examples:

        {% flowurl flow_cls 'viewflow:index' %}
        {% flowurl 'app_label/FlowCls' 'viewflow:index' %}
        {% flowurl 'app_label/FlowCls' 'viewflow:task_name' process_pk=1 task_pk=2 other_arg='value' %}
    """
    bits = token.split_contents()
    if len(bits) < 3:
        raise TemplateSyntaxError("'{}' takes at least two arguments (flow namespace)".format(bits[0]))

    kwargs = {}

    flow_ref = parser.compile_filter(bits[1])
    actionname = parser.compile_filter(bits[2])

    for bit in bits[3:]:
        match = kwarg_re.match(bit)
        if not match:
            raise TemplateSyntaxError("Malformed arguments in flow_url tag {}".format(bit))

        name, value = match.groups()
        if name:
            kwargs[name] = parser.compile_filter(value)

    return FlowURLNode(flow_ref, actionname, kwargs)


@register.assignment_tag
def flow_perm(user, task):
    """
    {% flow_perm request.user task as task_perm  %}
    """
    if not hasattr(task.flow_task, 'has_perm'):
        return False
    else:
        return task.flow_task.has_perm(user, task)
<commit_msg>Extend permission check<commit_after>import re

from django import template
from django.core.urlresolvers import reverse
from django.template.base import Node, TemplateSyntaxError
from django.utils.module_loading import import_by_path

from ..base import Flow
from ..compat import get_app_package


kwarg_re = re.compile(r"(\w+)=?(.+)")
register = template.Library()


class FlowURLNode(Node):
    def __init__(self, flow_ref, url_name, kwargs):
        self.flow_ref = flow_ref
        self.url_name = url_name
        self.kwargs = kwargs

    def render(self, context):
        # resolve flow reference
        flow_path = self.flow_ref.resolve(context)

        if isinstance(flow_path, Flow):
            flow_cls = flow_path
        else:
            try:
                app_label, flow_cls_path = flow_path.split('/')
            except ValueError:
                raise TemplateSyntaxError("Flow action should looks like app_label/FlowCls")

            app_package = get_app_package(app_label)
            if app_package is None:
                raise TemplateSyntaxError("{} app not found".format(app_label))

            flow_cls = import_by_path('{}.flows.{}'.format(app_package, flow_cls_path))

        # resolve url name and args
        url = self.url_name.resolve(context)
        kwargs = {key: value.resolve(context) for key, value in self.kwargs.items()}

        return reverse(url, current_app=flow_cls._meta.namespace, kwargs=kwargs)


@register.tag
def flowurl(parser, token):
    """
    Bound to flow {% url %} tag.

    Accepts flow namespace or flow class as first argument,
    and rest same as url tag Returns an absolute URL matching
    given flow action

    Examples:

        {% flowurl flow_cls 'viewflow:index' %}
        {% flowurl 'app_label/FlowCls' 'viewflow:index' %}
        {% flowurl 'app_label/FlowCls' 'viewflow:task_name' process_pk=1 task_pk=2 other_arg='value' %}
    """
    bits = token.split_contents()
    if len(bits) < 3:
        raise TemplateSyntaxError("'{}' takes at least two arguments (flow namespace)".format(bits[0]))

    kwargs = {}

    flow_ref = parser.compile_filter(bits[1])
    actionname = parser.compile_filter(bits[2])

    for bit in bits[3:]:
        match = kwarg_re.match(bit)
        if not match:
            raise TemplateSyntaxError("Malformed arguments in flow_url tag {}".format(bit))

        name, value = match.groups()
        if name:
            kwargs[name] = parser.compile_filter(value)

    return FlowURLNode(flow_ref, actionname, kwargs)


@register.assignment_tag
def flow_perm(user, task):
    """
    {% flow_perm request.user task as task_perm  %}
    """
    if not hasattr(task.flow_task, 'has_perm'):
        return False
    elif task.flow_task.has_perm(user, task):
        return True
    elif not hasattr(task.flow_task, 'can_be_assigned'):
        return False
    elif task.flow_task.can_be_assigned(user, task):
        return True

{'fraction_non_alphanumeric': 0.10258650821391121, 'fraction_numerical': 0.002446696959105208, 'mean_word_length': 2.851278600269179, 'pattern_counts': {'":': 0, '<': 5, '<?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': '3498293', 'n_tokens_mistral': 1735, 'n_tokens_neox': 1680, 'n_words': 442}