def create_model(model, val):
    """
    Creates a new model given a reference to it's class and a list of
    the values of it's variables.

    :param DjangoModel model:
        A reference to the class of the model that will be created.
    :param val: A list of pairs having the format(field name, field value).
    :type val: tuple(pair(str, .))
    :returns: A model with the values given.
    """
    vals_dictionary = dict(val)
    have_many_to_many_relation = any(x for x in list_of_fields(model)
                                     if (is_related(x) and
                                         'ManyToMany' in relation_type(x)))
    if not have_many_to_many_relation:
        mdl = model(**vals_dictionary)
        mdl.save()
        return mdl
    else:
        mdl = model()
        flds = list_of_fields(model)
        dict_T = {}
        for field in flds:
            dict_T[field.name] = relation_type(field)
        for key, val in vals_dictionary.items():
            if 'ManyToMany' not in dict_T[key]:
                setattr(mdl, key, val)
        mdl.save()
        for key, val in vals_dictionary.items():
            if 'ManyToMany' in dict_T[key]:
                for x in val:
                    getattr(mdl, key).add(x)
        mdl.save()
        return mdl
Ejemplo n.º 2
0
def field_sample_values(field):
    """ Field sample values

    Retrieves the list of sample values for a given field.

    Args :
        field : a reference to the class of the field.

    Returns :
    a list of sample values for the given field.
    """
    list_field_values = []
    if not is_auto_field(field):
        if is_reverse_related(field):
            # TODO(mostafa-mahmoud): Check if this case needs to be handled.
            pass
        elif is_related(field):
            model = field.rel.to
            list_field_values = list(model.objects.all())
            if 'ManyToMany' in relation_type(field) and list_field_values:
                siz = random.randint(1, len(list_field_values))
                list_field_values = [random.sample(list_field_values, siz)]
        else:
            found = False
            if hasattr(field.model, 'TestData'):
                model = field.model
                while (model.__base__ != Model
                       and not hasattr(model.TestData, field.name)):
                    model = model.__base__
                if field.name in model.TestData.__dict__.keys():
                    found = True
                    input_method = model.TestData.__dict__[field.name]
                    if isinstance(input_method, str):
                        app_name = field.model._meta.app_label
                        path = '%s/TestTemplates/%s' % (app_name, input_method)
                        input_file = open(path, 'r')
                        list_field_values = [word[:-1] for word in input_file]
                    elif (isinstance(input_method, list)
                          or isinstance(input_method, tuple)):
                        list_field_values = input_method
                    else:
                        if inspect.isfunction(input_method):
                            list_field_values = input_method()
            if not found:
                app_name = field.model._meta.app_label
                path = '%s/TestTemplates/sample__%s__%s' % (app_name,
                       field.model.__name__, field.name)
                if os.path.exists(path):
                    input_file = open(path, 'r')
                    list_field_values = [word[:-1] for word in input_file]
                else:
                    list_field_values = generate_random_values(field)
    return list(list_field_values)
def dependencies(model):
    """
    Retrieves the models the must be generated before a given model.

    :param DjangoModel model: A reference to the class of the given model.

    :rtype: List
    :returns: list of references to the classes of the models.
    """
    fields = list_of_fields(model)
    return [field.rel.to for field in fields
            if (is_required(field) and (is_related(field)
                and 'ManyToMany' not in relation_type(field)))]
def recompute(model, field):
    """
    Recompute the previously ignored fields in the models.

    :param DjangoModel model: A reference to the class of the given model.
    :param DjangoField field:
        A reference to the class of the non-computed field.
    :rtype: None
    """
    if is_related(field):
        models = model.objects.all()
        list_field_values = field_sample_values(field)
        random.shuffle(list_field_values)
        n = len(list_field_values)
        for index, mdl in enumerate(models):
            if ('ManyToMany' in relation_type(field) and
               not getattr(mdl, field.name).exists() or
               not is_required(field) and not getattr(mdl, field.name)):
                setattr(mdl, field.name, list_field_values[index % n])
                mdl.save()
def dfs(instances, cur_tuple, index, to_be_computed, constraints,
        model, to_be_shuffled):
    """
    Value generator for the fields of a given model by simulating
    a depth first search. The model will be saved in a (temporary) database.

    The interface of the predicate should be:
        boolean predicate(cur_tuple, model, field)
         - cur_tuple: List of tuples of the filled values of the field being
                      filled, in the format (str:field_name , field_value).
         - model: A reference to the class of the given model.
         - field: A reference to the class of the field being generated

         The function should handle that the given tuple might be not full,
         and it should depend that the previously generated models are stored
         in the temporary database, and it should return a boolean value that's
         true only if the required constraint is satisfied.

    :param int instances:
        The target number of generated instances of the model.
    :param cur_tuple:
        A list of pairs str:field_name, field_value of the values of
        the filled fields.
    :type cur_tuple: List(pair(str, .))
    :param int index:
        The index of the field being filled in the list of fields.
    :param List to_be_computed:
        A list used for accumulation of the ignored fields.
    :param List constraints:
        A list of predicate functions that will constraint the output.
    :param DjangoModel model: A reference to the class of the given model.
    :param boolean to_be_shuffled:
        A boolean variable that will determine if the sample data
        will be shuffled or not.
    :rtype: None
    """
    fields = list_of_fields(model)
    if index >= len(fields):
        dfs.total += 1
        create_model(model, cur_tuple)
        return 1
    else:
        list_field_values = field_sample_values(fields[index])
        if not list_field_values:
            many_to_many_related = (is_related(fields[index]) and 'ManyToMany'
                                    in relation_type(fields[index]))
            optional_field = not is_required(fields[index])
            auto_fld = is_auto_field(fields[index])
            if many_to_many_related or optional_field or auto_fld:
                if not is_auto_field(fields[index]):
                    to_be_computed.append(fields[index])
                return dfs(instances, cur_tuple, index + 1, to_be_computed,
                           constraints, model, to_be_shuffled)
        else:
            if to_be_shuffled:
                random.shuffle(list_field_values)
            instances_so_far = 0
            for field_id, nxt_field in enumerate(list_field_values):
                new_tuple = cur_tuple[:]
                new_tuple.append((fields[index].name, nxt_field))
                are_constraints_satisfied = True
                for cons in constraints:
                    if not cons(new_tuple, model, fields[index]):
                        are_constraints_satisfied = False
                        break
                if are_constraints_satisfied:
                    instances_remaining = instances - instances_so_far
                    remaining_values = len(list_field_values) - field_id
                    value_instances = ((instances_remaining - 1 +
                                       remaining_values) / remaining_values)
                    new_instances = dfs(value_instances, new_tuple, index + 1,
                                        to_be_computed, constraints, model,
                                        to_be_shuffled)
                    instances_so_far += new_instances
                    if instances_so_far >= instances or dfs.total >= dfs.size:
                        return instances_so_far
            return instances_so_far
Ejemplo n.º 6
0
def dfs(cur_tuple, index, to_be_computed, constraints, model, to_be_shuffled):
    """ Depth first search

    Generates values for the fields of a given model by simulating
    a depth first search.

    Args :
        cur_tuple : current tuple, a tuple of the values of the filled fields.
        index : the index of the field being filled in the list of fields.
        to_be_computed : A list used for accumulation of the ignored fields.
        constraints : a list of utility, that will constraint the output.
        model : a reference to the class of the given model.
        to_be_shuffled : A boolean variable that will determine if the sample
                         data will be shuffled or not.

    Returns:
        None

    The model will be saved in a temporary database.

    The interface of the predicate should be :
        predicate(cur_tuple, model, field)
            where:
                - cur_tuple : list of tuples of the filled values of the field
                              being filled, in the
                              format (field name , field value).

                - model : a reference to the class of the given model.

                - field : A reference to the class of the field being generated

         The function should handle that the given tuple might be not full,
         and it should depend that the previously generated models are stored
         in the temporary database, and it should return a boolean value that's
         true only if the required constraint is satisfied.

    """
    fields = list_of_fields(model)
    if dfs.size <= 0:
        return True
    if index >= len(fields):
        dfs.size -= 1
        create_model(model, cur_tuple)
    else:
        list_field_values = field_sample_values(fields[index])
        if not list_field_values:
            many_to_many_related = (is_related(fields[index]) and 'ManyToMany'
                                    in relation_type(fields[index]))
            optional_field = not is_required(fields[index])
            auto_fld = is_auto_field(fields[index])
            if many_to_many_related or optional_field or auto_fld:
                if not is_auto_field(fields[index]):
                    to_be_computed.append(fields[index])
                return dfs(cur_tuple, index + 1, to_be_computed,
                           constraints, model, to_be_shuffled)
        else:
            if to_be_shuffled:
                random.shuffle(list_field_values)
            for nxt_field in list_field_values:
                new_tuple = cur_tuple[:]
                new_tuple.append((fields[index].name, nxt_field))
                are_constraints_satisfied = True
                for cons in constraints:
                    if not cons(new_tuple, model, fields[index]):
                        are_constraints_satisfied = False
                        break
                if are_constraints_satisfied:
                    is_done = dfs(new_tuple, index + 1, to_be_computed,
                                  constraints, model, to_be_shuffled)
                    if is_done:
                        return True