<commit_before>from .parser import Parser
from curious import model_registry
from curious.graph import step_one


class Query(object):

  def __init__(self, query):
    parser = Parser(query)
    self.__query = query
    self.__obj_query = parser.object_query
    self.__steps = parser.steps
    self.__validate()


  @property
  def query_string(self):
    return self.__query


  @staticmethod
  def _validate(query):
    """
    Validate a query. A query is an array whose elements are model
    relationships or subqueries. This function checks each model relationship
    to make sure the model and the relationship exist.
    """

    for rel in query:
      if 'subquery' in rel:
        Query._validate(rel['subquery'])
      else:
        model = rel['model']
        method = rel['method']
        if method is None:
          model_registry.getclass(model)
        else:
          model_registry.getattr(model, method)


  def __validate(self):
    Query._validate([self.__obj_query]+self.__steps)


  def __get_objects(self):
    """
    Get initial objects from object query.
    """

    model = self.__obj_query['model']
    method = self.__obj_query['method']
    filters = self.__obj_query['filters']
    if '__id__' in filters:
      filters['pk'] = filters['__id__']
      del filters['__id__']
    if method is None:
      cls = model_registry.getclass(model)
      if '__exclude__' in filters:
        ff = {k: v for k, v in filters.iteritems() if k != '__exclue__'}
        return cls.objects.exclude(**ff)
      else:
        x = cls.objects.filter(**filters)
        return x
    else:
      f = model_registry.getattr(model, method)
      return f(**filters)


  @staticmethod
  def _graph_step(obj_src, step_f, filters):
    """
    Traverse one step on the graph. Takes in and returns arrays of output,
    input object tuples. The input objects in the tuples are from start of the
    query, not start of this step.
    """

    next_obj_src = step_one([obj for obj, src in obj_src], step_f, filters)

    keep = []
    for next_obj, next_src in next_obj_src:
      # find next_src in original obj_src
      for obj, src in obj_src:
        if obj.pk == next_src:
          keep.append((next_obj, src))

    return list(set(keep))


  @staticmethod
  def _recursive_rel(obj_src, step_f, filters, need_terminal):
    """
    Traverse a relationship recursively. Collected objects, either loop
    terminating objects or loop continuing objects. Returns arrays of output,
    input object tuples. The input objects in the tuples are from start of the
    query, not start of this step.
    """

    collected = []

    while len(obj_src) > 0:
      # get objects that can continue, w/ filters
      next_obj_src = Query._graph_step(obj_src, step_f, filters)

      if need_terminal:
        # get all reachable objects, w/o filtering
        reachable = Query._graph_step(obj_src, step_f)
        for tup in reachable:
          if tup not in next_obj_src:
            if tup not in collected:
              collected.append(tup)
      else:
        for tup in next_obj_src:
          if tup not in collected:
            collected.append(tup)

      obj_src = next_obj_src

    return collected


  @staticmethod
  def _rel_step(obj_src, step):
    """<commit_msg>Better behavior for ** when there are no filters<commit_after>from .parser import Parser
from curious import model_registry
from curious.graph import step_one


class Query(object):

  def __init__(self, query):
    parser = Parser(query)
    self.__query = query
    self.__obj_query = parser.object_query
    self.__steps = parser.steps
    self.__validate()


  @property
  def query_string(self):
    return self.__query


  @staticmethod
  def _validate(query):
    """
    Validate a query. A query is an array whose elements are model
    relationships or subqueries. This function checks each model relationship
    to make sure the model and the relationship exist.
    """

    for rel in query:
      if 'subquery' in rel:
        Query._validate(rel['subquery'])
      else:
        model = rel['model']
        method = rel['method']
        if method is None:
          model_registry.getclass(model)
        else:
          model_registry.getattr(model, method)


  def __validate(self):
    Query._validate([self.__obj_query]+self.__steps)


  def __get_objects(self):
    """
    Get initial objects from object query.
    """

    model = self.__obj_query['model']
    method = self.__obj_query['method']
    filters = self.__obj_query['filters']
    if '__id__' in filters:
      filters['pk'] = filters['__id__']
      del filters['__id__']
    if method is None:
      cls = model_registry.getclass(model)
      if '__exclude__' in filters:
        ff = {k: v for k, v in filters.iteritems() if k != '__exclue__'}
        return cls.objects.exclude(**ff)
      else:
        x = cls.objects.filter(**filters)
        return x
    else:
      f = model_registry.getattr(model, method)
      return f(**filters)


  @staticmethod
  def _graph_step(obj_src, step_f, filters):
    """
    Traverse one step on the graph. Takes in and returns arrays of output,
    input object tuples. The input objects in the tuples are from start of the
    query, not start of this step.
    """

    next_obj_src = step_one([obj for obj, src in obj_src], step_f, filters)

    keep = []
    for next_obj, next_src in next_obj_src:
      # find next_src in original obj_src
      for obj, src in obj_src:
        if obj.pk == next_src:
          keep.append((next_obj, src))

    return list(set(keep))


  @staticmethod
  def _recursive_rel(obj_src, step_f, filters, need_terminal):
    """
    Traverse a relationship recursively. Collected objects, either loop
    terminating objects or loop continuing objects. Returns arrays of output,
    input object tuples. The input objects in the tuples are from start of the
    query, not start of this step.
    """

    collected = []

    while len(obj_src) > 0:
      next_obj_src = Query._graph_step(obj_src, step_f, filters)

      if need_terminal and (filters is None or filters == {}):
        # traverse one step from last set of nodes
        src = [(t[0], t[0].pk) for t in obj_src]
        progressed = Query._graph_step(src, step_f, filters)
        progressed = [t[1] for t in progressed]
        for tup in obj_src:
          # if we didn't progress, than collect
          if tup[0].pk not in progressed:
            if tup not in collected:
              collected.append(tup)

      elif need_terminal:
        # get all reachable objects, w/o filtering
        reachable = Query._graph_step(src, step_f, None)
        for tup in reachable:
          if tup not in next_obj_src:
            if tup not in collected:
              collected.append(tup)

      else: # need all intermediate
        for tup in next_obj_src:
          if tup not in collected:
            collected.append(tup)

      obj_src = next_obj_src

    return collected


  @staticmethod
  def _rel_step(obj_src, step):
    """
{'fraction_non_alphanumeric': 0.08739376770538243, 'fraction_numerical': 0.0008498583569405099, 'mean_word_length': 2.562563067608476, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, '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': '2798533', 'n_tokens_mistral': 2149, 'n_tokens_neox': 2080, 'n_words': 696}