<commit_before>##########################################################################
#          (C) Vrije Universiteit, Amsterdam (the Netherlands)            #
#                                                                         #
# This file is part of AmCAT - The Amsterdam Content Analysis Toolkit     #
#                                                                         #
# AmCAT is free software: you can redistribute it and/or modify it under  #
# the terms of the GNU Affero General Public License as published by the  #
# Free Software Foundation, either version 3 of the License, or (at your  #
# option) any later version.                                              #
#                                                                         #
# AmCAT is distributed in the hope that it will be useful, but WITHOUT    #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or   #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public     #
# License for more details.                                               #
#                                                                         #
# You should have received a copy of the GNU Affero General Public        #
# License along with AmCAT.  If not, see <http://www.gnu.org/licenses/>.  #
###########################################################################
import StringIO
import csv
import json
from django import forms
from django.core.exceptions import ValidationError
from amcat.scripts.query import QueryAction, QueryActionForm, QueryActionHandler
from amcat.tools.association import FORMATS, INTERVALS, Association
from amcat.tools.keywordsearch import SelectionSearch


def get_content_type(form):
    return form.cleaned_data["output_type"].split(";")


class AssociationForm(QueryActionForm):
    number_format = forms.ChoiceField(choices=((c, c) for c in FORMATS), required=True)
    interval = forms.ChoiceField(choices=((str(i), str(i)) for i in INTERVALS), required=False, initial="None")
    weigh = forms.BooleanField(label="Weigh for number of hits", required=False)

    graph_threshold = forms.DecimalField(label="Graph: threshold", required=False, initial=0.0)
    graph_label = forms.BooleanField(label="Graph: include association in label", required=False)

    def clean_interval(self):
        interval = self.cleaned_data["interval"]
        return None if interval == "None" else interval

    def clean(self):
        super(AssociationForm, self).clean()
        output_type, meaning = get_content_type(self)

        if self.cleaned_data["interval"] and output_type == "text/csv" and meaning == "cross":
            error_msg = "You cannot export crosstables to text/csv if an interval is specified"
            raise ValidationError(error_msg)

        return self.cleaned_data

class AssociationHandler(QueryActionHandler):

    def get_response(self):
        response = super(AssociationHandler, self).get_response()
        content_type = get_content_type(self.get_query_action().get_form())[0]

        if content_type == "text/csv":
            response["Content-Disposition"] = 'attachment; filename="association.csv"'

        return response

class AssociationAction(QueryAction):
    form_class = AssociationForm
    task_handler = AssociationHandler

    output_types = (
        ("application/json+table;fromto", "Table (from-to)"),
        ("application/json+crosstables;cross", "Table (cross)"),
        ("text/csv;fromto", "CSV (from-to)"),
        ("text/csv;cross", "CSV (cross)"),
        ("text/csv;cross", "CSV (cross)"),
        ("application/json+image+svg+multiple;", "Graph"),
    )


    def get_association(self, form):
        selection = SelectionSearch(form)<commit_msg>Fixed double CSV cross table in association outputs closes #444<commit_after>##########################################################################
#          (C) Vrije Universiteit, Amsterdam (the Netherlands)            #
#                                                                         #
# This file is part of AmCAT - The Amsterdam Content Analysis Toolkit     #
#                                                                         #
# AmCAT is free software: you can redistribute it and/or modify it under  #
# the terms of the GNU Affero General Public License as published by the  #
# Free Software Foundation, either version 3 of the License, or (at your  #
# option) any later version.                                              #
#                                                                         #
# AmCAT is distributed in the hope that it will be useful, but WITHOUT    #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or   #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public     #
# License for more details.                                               #
#                                                                         #
# You should have received a copy of the GNU Affero General Public        #
# License along with AmCAT.  If not, see <http://www.gnu.org/licenses/>.  #
###########################################################################
import StringIO
import csv
import json
from django import forms
from django.core.exceptions import ValidationError
from amcat.scripts.query import QueryAction, QueryActionForm, QueryActionHandler
from amcat.tools.association import FORMATS, INTERVALS, Association
from amcat.tools.keywordsearch import SelectionSearch


def get_content_type(form):
    return form.cleaned_data["output_type"].split(";")


class AssociationForm(QueryActionForm):
    number_format = forms.ChoiceField(choices=((c, c) for c in FORMATS), required=True)
    interval = forms.ChoiceField(choices=((str(i), str(i)) for i in INTERVALS), required=False, initial="None")
    weigh = forms.BooleanField(label="Weigh for number of hits", required=False)

    graph_threshold = forms.DecimalField(label="Graph: threshold", required=False, initial=0.0)
    graph_label = forms.BooleanField(label="Graph: include association in label", required=False)

    def clean_interval(self):
        interval = self.cleaned_data["interval"]
        return None if interval == "None" else interval

    def clean(self):
        super(AssociationForm, self).clean()
        output_type, meaning = get_content_type(self)

        if self.cleaned_data["interval"] and output_type == "text/csv" and meaning == "cross":
            error_msg = "You cannot export crosstables to text/csv if an interval is specified"
            raise ValidationError(error_msg)

        return self.cleaned_data

class AssociationHandler(QueryActionHandler):

    def get_response(self):
        response = super(AssociationHandler, self).get_response()
        content_type = get_content_type(self.get_query_action().get_form())[0]

        if content_type == "text/csv":
            response["Content-Disposition"] = 'attachment; filename="association.csv"'

        return response

class AssociationAction(QueryAction):
    form_class = AssociationForm
    task_handler = AssociationHandler

    output_types = (
        ("application/json+table;fromto", "Table (from-to)"),
        ("application/json+crosstables;cross", "Table (cross table)"),
        ("text/csv;fromto", "CSV (from-to)"),
        ("text/csv;cross", "CSV (cross table)"),
        ("application/json+image+svg+multiple;", "Graph"),
    )


    def get_association(self, form):
        selection = SelectionSearch(form)
{'fraction_non_alphanumeric': 0.12853914661704108, 'fraction_numerical': 0.0014621826399042934, 'mean_word_length': 2.5862726406101046, 'pattern_counts': {'":': 4, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 32, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4312865', 'n_tokens_mistral': 1841, 'n_tokens_neox': 1773, 'n_words': 563}