<commit_before>import inspect
import json

from django.core.urlresolvers import reverse
from django.shortcuts import render

from django_maced.utils.get_html_code_functions import get_items_html_code_for_text, \
    get_items_html_code_for_color, get_items_html_code_for_select, get_html_code_for_options

BAD_ITEM_NAME_CHARACTERS = (".", ":", "#", "$", "*")
ACTION_TYPES = ["add", "edit", "merge", "delete"]  # Action types of "clone" and "info" will be added later.
                                                   # "info" is not really an action, but for the sake of ease of use,
                                                   # it will be considered one.


# The main function to craft html code for each item. This is the only function that should be called directly besides
#       finalize_context_for_items().
# item_name is the name of the model in most cases. You could potentially have 2 of the same model on a page, however
#       this will currently requires you to have 2 sets of urls which is kind of dumb, but still possible.
# item_html_name is the name that will show up on the frontend to the users. This is also the name used on the modals.
# item_class is the class of the model. Be sure to send in the class, not the instance of the class.
# item_name_field_name is the name of the field that stores the name for this model. Example: You have a model called
#       Gender. It will have some kind of field to identify the gender by. This will likely be called "name", but
#       could be called anything so it is required to be able to identify the object on the frontend.
# field_list is the specially formatted list of fields and their info. For more information please refer to the
#       README.md file.
# name_of_app_with_urls is the name of the app that has the urls that will be used for performing all of the actions
#       from django_maced. Please note that url names should be named according to AppName.Action_ItemName. Example:
#       App name is component_manager and the item is component. The url names should be
#       "component_manager.add_component", "component_manager.edit_component", etc
# current_item_id is the id of the item that will be selected by default on the frontend when you first land on the
#       page. If you do not need one preselected, use 0. Since it can be tedious to get the current_item_id for each
#       object if you have several for a page, you can simply use the get_current_item_id(model_instance, field_name)
#       function. Just pass it your related model and the field name of the field that this item represents. Example:
#       You have a model called Person with an attribute called City but it is not a required field for this Person
#       object. You want City to be a django_maced item, but you don't want to have to check if city is there for this
#       person, because if it doesn't you won't be able to say person.city.id because id isn't on None. Of course, you
#       can do this manually, but if you have several of these, it could be annoying and the code will look cluttered.
#       Instead use get_current_item_id(person, "city") and it will do the work for you and raise errors appropriately.
#       If city isn't set for this person, it will return 0, which will result in the first select item to be
#       preselected (should be a blank entry in the select in this case since city isn't required).
# allow_empty simply sets whether or not a blank will be inserted into the select. This defaults to True. Set this to
#       False if you want this field to be required. One caveat is that if you don't have any instances of this model
#       in the system yet and you make it required, nothing will prevent it from allowing you to submit the form and
#       will have to be handled on the backend. Perhaps this can be changed in the future.
# field_to_order_by is the field to order your select by. It defaults to None which converts to item_name_field_name.
#       Note that you can add "-" in front of the field_to_order_by to make it descending order.
def add_item_to_context(context, item_name, item_html_name, item_class, item_name_field_name, field_list,
                        name_of_app_with_urls, current_item_id, allow_empty=True, field_to_order_by=None):
    if not isinstance(context, dict):
        raise TypeError("Please provide a valid context")

    if not isinstance(item_name, (str, unicode)):
        raise TypeError("item_name must be a string")

    if not inspect.isclass(item_class):
        raise TypeError("item_class must be a class")

    if not isinstance(item_name_field_name, (str, unicode)):
        raise TypeError("object_name_field_name must be a string")

    if not isinstance(field_list, list):
        raise TypeError("field_list must be a list")

    if not isinstance(name_of_app_with_urls, (str, unicode)):
        raise TypeError("name_of_app_with_urls must be a string")

    if not isinstance(allow_empty, bool):
        raise TypeError("allow_empty must be a bool")

    if field_to_order_by is None:
        field_to_order_by = item_name_field_name

    if not isinstance(field_to_order_by, (str, unicode)):
        raise TypeError("field_to_order_by must be a string that is the name of the field you want to order your objects by")

    if "maced_data" not in context:
        context["maced_data"] = {}

    if "maced_modals" not in context:
        context["maced_modals"] = ""

    maced_data = context["maced_data"]

    if "item_names" not in maced_data:
        maced_data["item_names"] = []

    if "field_names" not in maced_data:
        maced_data["field_names"] = {}

    if "get_urls" not in maced_data:
        maced_data["get_urls"] = {}

    html_code_dictionary = {}
    html_code_dictionary[item_name] = {}

    for action_type in ACTION_TYPES:
        html_code_dictionary[item_name][action_type] = ""

    add_base_url = name_of_app_with_urls + ".add_" + item_name
    edit_base_url = name_of_app_with_urls + ".edit_" + item_name
    merge_base_url = name_of_app_with_urls + ".merge_" + item_name
    delete_base_url = name_of_app_with_urls + ".delete_" + item_name
    get_base_url = name_of_app_with_urls + ".get_" + item_name

    add_url = reverse(add_base_url)
    edit_url = reverse(edit_base_url, args=["0"])[:-2]  # A number is required to get the url, then we cut it off with [:-2]  # noqa
    merge_url = reverse(merge_base_url, args=["0", "0"])[:-4]  # A number is required to get the url, then we cut it off with [:-4]  # noqa
    delete_url = reverse(delete_base_url, args=["0"])[:-2]  # A number is required to get the url, then we cut it off with [:-2]  # noqa
    get_url = reverse(get_base_url, args=["0"])[:-2]  # A number is required to get the url, then we cut it off with [:-2]  # noqa

    maced_data["get_urls"][item_name] = get_url
    field_name_list = []

    # Get all items of this type
    items = get_items(item_class)

    # Create an item_options_list which is a list of tuples defined as (id_of_the_item, name_of_the_item). This will
    # be used in the merge function.
    item_options_list = [(item.id, getattr(item, item_name_field_name)) for item in items]

    maced_object_option_html_code = get_html_code_for_options(item_options_list)

    # Merge has special html before the regular html
    html_code_dictionary[item_name]["merge"] = \
        '<table class="table table-striped">' + \
            '<tr>' + \
                '<th></th>' + \
                '<td>' + \
                    '<select class="form-control" id="merge-' + item_name + '1-input" disabled >' + maced_object_option_html_code + '</select>' + \
                '</td>' + \
                '<td style="text-align: center;">' + \
                    '<b> Resulting ' + str(item_html_name) + ' </b>' + \
                '</td>' + \
                '<td>' + \
                    '<select class="form-control" id="merge-' + item_name + '2-input">' + maced_object_option_html_code + '</select>' + \
                '</td>' + \
            '</tr>'

    # Create html input fields for each field on the model
    for field in field_list:
        if "type" not in field:
            field["type"] = "text"

        if "html_name" not in field:
            field["html_name"] = field["name"].title()

        insert_items_html_code(html_code_dictionary, item_name, field["type"], field["html_name"], field["name"])
        field_name_list.append(field["name"])

    # Merge has special html after the regular html<commit_msg>Added some validation to fields. Fixed bug where you couldn't pass the select options to the fields of type select.<commit_after>import inspect
import json

from django.core.urlresolvers import reverse
from django.shortcuts import render

from django_maced.utils.get_html_code_functions import get_items_html_code_for_text, \
    get_items_html_code_for_color, get_items_html_code_for_select, get_html_code_for_options

BAD_ITEM_NAME_CHARACTERS = (".", ":", "#", "$", "*")
ACTION_TYPES = ["add", "edit", "merge", "delete"]  # Action types of "clone" and "info" will be added later.
                                                   # "info" is not really an action, but for the sake of ease of use,
                                                   # it will be considered one.


# The main function to craft html code for each item. This is the only function that should be called directly besides
#       finalize_context_for_items().
# item_name is the name of the model in most cases. You could potentially have 2 of the same model on a page, however
#       this will currently requires you to have 2 sets of urls which is kind of dumb, but still possible.
# item_html_name is the name that will show up on the frontend to the users. This is also the name used on the modals.
# item_class is the class of the model. Be sure to send in the class, not the instance of the class.
# item_name_field_name is the name of the field that stores the name for this model. Example: You have a model called
#       Gender. It will have some kind of field to identify the gender by. This will likely be called "name", but
#       could be called anything so it is required to be able to identify the object on the frontend.
# field_list is the specially formatted list of fields and their info. For more information please refer to the
#       README.md file.
# name_of_app_with_urls is the name of the app that has the urls that will be used for performing all of the actions
#       from django_maced. Please note that url names should be named according to AppName.Action_ItemName. Example:
#       App name is component_manager and the item is component. The url names should be
#       "component_manager.add_component", "component_manager.edit_component", etc
# current_item_id is the id of the item that will be selected by default on the frontend when you first land on the
#       page. If you do not need one preselected, use 0. Since it can be tedious to get the current_item_id for each
#       object if you have several for a page, you can simply use the get_current_item_id(model_instance, field_name)
#       function. Just pass it your related model and the field name of the field that this item represents. Example:
#       You have a model called Person with an attribute called City but it is not a required field for this Person
#       object. You want City to be a django_maced item, but you don't want to have to check if city is there for this
#       person, because if it doesn't you won't be able to say person.city.id because id isn't on None. Of course, you
#       can do this manually, but if you have several of these, it could be annoying and the code will look cluttered.
#       Instead use get_current_item_id(person, "city") and it will do the work for you and raise errors appropriately.
#       If city isn't set for this person, it will return 0, which will result in the first select item to be
#       preselected (should be a blank entry in the select in this case since city isn't required).
# allow_empty simply sets whether or not a blank will be inserted into the select. This defaults to True. Set this to
#       False if you want this field to be required. One caveat is that if you don't have any instances of this model
#       in the system yet and you make it required, nothing will prevent it from allowing you to submit the form and
#       will have to be handled on the backend. Perhaps this can be changed in the future.
# field_to_order_by is the field to order your select by. It defaults to None which converts to item_name_field_name.
#       Note that you can add "-" in front of the field_to_order_by to make it descending order.
def add_item_to_context(context, item_name, item_html_name, item_class, item_name_field_name, field_list,
                        name_of_app_with_urls, current_item_id, allow_empty=True, field_to_order_by=None):
    if not isinstance(context, dict):
        raise TypeError("Please provide a valid context")

    if not isinstance(item_name, (str, unicode)):
        raise TypeError("item_name must be a string")

    if not inspect.isclass(item_class):
        raise TypeError("item_class must be a class")

    if not isinstance(item_name_field_name, (str, unicode)):
        raise TypeError("object_name_field_name must be a string")

    if not isinstance(field_list, list):
        raise TypeError("field_list must be a list")

    if not isinstance(name_of_app_with_urls, (str, unicode)):
        raise TypeError("name_of_app_with_urls must be a string")

    if not isinstance(allow_empty, bool):
        raise TypeError("allow_empty must be a bool")

    if field_to_order_by is None:
        field_to_order_by = item_name_field_name

    if not isinstance(field_to_order_by, (str, unicode)):
        raise TypeError("field_to_order_by must be a string that is the name of the field you want to order your objects by")

    if "maced_data" not in context:
        context["maced_data"] = {}

    if "maced_modals" not in context:
        context["maced_modals"] = ""

    maced_data = context["maced_data"]

    if "item_names" not in maced_data:
        maced_data["item_names"] = []

    if "field_names" not in maced_data:
        maced_data["field_names"] = {}

    if "get_urls" not in maced_data:
        maced_data["get_urls"] = {}

    html_code_dictionary = {}
    html_code_dictionary[item_name] = {}

    for action_type in ACTION_TYPES:
        html_code_dictionary[item_name][action_type] = ""

    add_base_url = name_of_app_with_urls + ".add_" + item_name
    edit_base_url = name_of_app_with_urls + ".edit_" + item_name
    merge_base_url = name_of_app_with_urls + ".merge_" + item_name
    delete_base_url = name_of_app_with_urls + ".delete_" + item_name
    get_base_url = name_of_app_with_urls + ".get_" + item_name

    add_url = reverse(add_base_url)
    edit_url = reverse(edit_base_url, args=["0"])[:-2]  # A number is required to get the url, then we cut it off with [:-2]  # noqa
    merge_url = reverse(merge_base_url, args=["0", "0"])[:-4]  # A number is required to get the url, then we cut it off with [:-4]  # noqa
    delete_url = reverse(delete_base_url, args=["0"])[:-2]  # A number is required to get the url, then we cut it off with [:-2]  # noqa
    get_url = reverse(get_base_url, args=["0"])[:-2]  # A number is required to get the url, then we cut it off with [:-2]  # noqa

    maced_data["get_urls"][item_name] = get_url
    field_name_list = []

    # Get all items of this type
    items = get_items(item_class)

    # Create an item_options_list which is a list of tuples defined as (id_of_the_item, name_of_the_item). This will
    # be used in the merge function.
    item_options_list = [(item.id, getattr(item, item_name_field_name)) for item in items]

    maced_object_option_html_code = get_html_code_for_options(item_options_list)

    # Merge has special html before the regular html
    html_code_dictionary[item_name]["merge"] = \
        '<table class="table table-striped">' + \
            '<tr>' + \
                '<th></th>' + \
                '<td>' + \
                    '<select class="form-control" id="merge-' + item_name + '1-input" disabled >' + maced_object_option_html_code + '</select>' + \
                '</td>' + \
                '<td style="text-align: center;">' + \
                    '<b> Resulting ' + str(item_html_name) + ' </b>' + \
                '</td>' + \
                '<td>' + \
                    '<select class="form-control" id="merge-' + item_name + '2-input">' + maced_object_option_html_code + '</select>' + \
                '</td>' + \
            '</tr>'

    # Create html input fields for each field on the model
    for field in field_list:
        extra_info = None

        if "name" not in field:
            raise ValueError("Field in field_list is missing \"name\"")

        if "type" not in field:
            field["type"] = "text"

        if field["type"] == "select":
            if "options" in field:
                extra_info = field["options"]
            else:
                raise ValueError("Field " + str(field["name"]) + " in field_list is set to type \"select\", but doesn't have \"options\"")

        if "html_name" not in field:
            field["html_name"] = field["name"].title()

        insert_items_html_code(html_code_dictionary, item_name, field["type"], field["html_name"], field["name"], extra_info)
        field_name_list.append(field["name"])

    # Merge has special html after the regular html
{'fraction_non_alphanumeric': 0.08264556889976664, 'fraction_numerical': 0.0021629005634925154, 'mean_word_length': 3.053056516724337, 'pattern_counts': {'":': 3, '<': 37, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3292902', 'n_tokens_mistral': 5168, 'n_tokens_neox': 5057, 'n_words': 2049}