"""
Functions for filtering the experiments based on conditions.
"""
# standard library
from copy import deepcopy
# Django
from django.conf import settings
# DISBi
from disbi.utils import clean_set
[docs]def combine_on_sep(items, separator):
"""
Combine each item with each other item on a `separator`.
Args:
items (list): A list or iterable that remembers order.
separator (str): The SEPARATOR the items will be combined on.
Returns:
list: A list with all the combined items as strings.
"""
combined_items = []
# Combine items only if there is more than 1 items.
if len(items) > 1:
# Convert the empty string back to minus.
items = [i if i!='' else '-' for i in items]
for i, item in enumerate(items):
reduced_items = items[:i] + items[i+1:]
combined_with_item = [separator.join((item, r)) for r in reduced_items]
combined_items += combined_with_item
# Else simply return the given list.
else:
combined_items = items
return combined_items
[docs]def combine_conditions(conditions, combinable_conditions):
"""
Apply :func:`combine_on_sep` to each value in a dictionary.
Args:
conditions (dict): Dictionary with a list of condition values.
Returns:
dict: A dictionary with the same keys and lists of combined values.
"""
combined_conditions = {}
for k, values in conditions.items():
if k in combinable_conditions:
combined_conditions[k] = combine_on_sep(values, settings.DISBI['SEPARATOR'])
else:
combined_conditions[k] = values
return combined_conditions
[docs]def get_experiments_by_condition(conditions, experiment_model):
"""
Return a set of experiments that match the conditions.
Args:
conditions (dict): A dictionary with conditions as keys and a list of values.
Returns:
set: A set of experiments that match the conditions.
"""
# If nothing was chosen conditions is an empty dict and
# evaluates to false.
if not conditions:
return set()
query_conditions = lookup_format(conditions)
# Experiments from parameters.
exps_by_condition = set(experiment_model.objects.filter(**query_conditions))
# Experimental parameters that can be combined in a microarray experiment.
combinable_conditions = [field.name for field in experiment_model._meta.get_fields()
if getattr(field, 'di_combinable', False)]
combined_conditions = combine_conditions(conditions, combinable_conditions)
combined_query_conditions = lookup_format(combined_conditions)
# Experiments from all combinable conditions combined.
exps_by_combined_condtion = set(experiment_model.objects.filter(**combined_query_conditions) or ())
# Experiments from a single combinable condition, combined each.
for combinable_condition in combinable_conditions:
if combinable_condition in conditions.keys():
c_conditions = deepcopy(conditions)
c_conditions[combinable_condition] = combine_on_sep(conditions[combinable_condition],
settings.DISBI['SEPARATOR'])
c_combined_query_conditons = lookup_format(c_conditions)
exps_by_combined_condtion |= set(experiment_model.objects.filter(
**c_combined_query_conditons) or ())
return exps_by_condition | exps_by_combined_condtion
[docs]def get_requested_experiments(formset_list, experiment_model):
"""
Return all experiments that match the request from the form.
Args:
formset_list (list): Formsets containing POST data.
Returns:
set: The union of the set of the directly requested experiments
and those that matched the requested conditons.
"""
# Formsets with these prefixes return model instances,
# thus no further query is needed.
no_query = ['experiment']
conditions = {}
for formset in formset_list:
if formset.prefix not in no_query:
conditions.update(clean_set(formset.cleaned_data))
elif formset.prefix == 'experiment':
# Directly requested experiments.
directly_req_exps = (set(
clean_set(formset.cleaned_data).get('experiment') or ())
)
exps_from_conditions = get_experiments_by_condition(conditions, experiment_model)
return directly_req_exps | exps_from_conditions