text: import re
  from functools import reduce
  from pyparsing import (
      infixNotation,
      opAssoc,
      Optional,
      Literal,
      CharsNotIn,
      ParseException,
  )
  import logging
  from logging import Filter
  
  from django.apps import apps
  from django.db import models
  from django.conf import settings
  
  from awx.main.constants import LOGGER_BLACKLIST
  from awx.main.utils.common import get_search_fields
  
  __all__ = ['SmartFilter', 'ExternalLoggerEnabled', 'DynamicLevelFilter']
  
  logger = logging.getLogger('awx.main.utils')
  
  
  class FieldFromSettings(object):
      """
      Field interface - defaults to getting value from setting
      if otherwise set, provided value will take precedence
          over value in settings
      """
  
      def __init__(self, setting_name):
          self.setting_name = setting_name
  
      def __get__(self, instance, type=None):
          if self.setting_name in getattr(instance, 'settings_override', {}):
              return instance.settings_override[self.setting_name]
          return getattr(settings, self.setting_name, None)
  
      def __set__(self, instance, value):
          if value is None:
              if hasattr(instance, 'settings_override'):
                  instance.settings_override.pop('instance', None)
          else:
              if not hasattr(instance, 'settings_override'):
                  instance.settings_override = {}
              instance.settings_override[self.setting_name] = value
  
  
  def record_is_blacklisted(record):
      """Given a log record, return True if it is considered to be in
      the logging blacklist, return False if not
      """
      for logger_name in LOGGER_BLACKLIST:
          if record.name.startswith(logger_name):
              return True
      return False
  
  
  class ExternalLoggerEnabled(Filter):
  
      enabled_loggers = FieldFromSettings('LOG_AGGREGATOR_LOGGERS')
      enabled_flag = FieldFromSettings('LOG_AGGREGATOR_ENABLED')
  
      def __init__(self, **kwargs):
          super(ExternalLoggerEnabled, self).__init__()
          for field_name, field_value in kwargs.items():
              if not isinstance(ExternalLoggerEnabled.__dict__.get(field_name, None), FieldFromSettings):
                  raise Exception('%s is not a valid kwarg' % field_name)
              if field_value is None:
                  continue
              setattr(self, field_name, field_value)
  
      def filter(self, record):
          """Filters out all log records if LOG_AGGREGATOR_ENABLED is False
          or if the particular logger is not in LOG_AGGREGATOR_LOGGERS
          should only be used for the external logger
  
          False - should not be logged
          True - should be logged
          """
          # Do not send exceptions to external logger
          if record_is_blacklisted(record):
              return False
          # General enablement
          if not self.enabled_flag:
              return False
  
          # Logger type enablement
          loggers = self.enabled_loggers
          if not loggers:
              return False
          if record.name.startswith('awx.analytics'):
              base_path, headline_name = record.name.rsplit('.', 1)
              return bool(headline_name in loggers)
          else:
              if '.' in record.name:
                  base_name, trailing_path = record.name.split('.', 1)
              else:
                  base_name = record.name
              return bool(base_name in loggers)
  
  
  class DynamicLevelFilter(Filter):
  
      def filter(self, record):
          """Filters out logs that have a level below the threshold defined
          by the databse setting LOG_AGGREGATOR_LEVEL
          """
          if record_is_blacklisted(record):
              # Fine to write blacklisted loggers to file, apply default filtering level
              cutoff_level = logging.WARNING
          else:
              try:
                  cutoff_level = logging._nameToLevel[settings.LOG_AGGREGATOR_LEVEL]
              except Exception:
                  cutoff_level = logging.WARNING
  
          return bool(record.levelno >= cutoff_level)
  
  
  def string_to_type(t):
      if t == u'null':
          return None
      if t == u'true':
          return True
      elif t == u'false':
          return False
  
      if re.search(r'^[-+]?[0-9]+$',t):
          return int(t)
  
      if re.search(r'^[-+]?[0-9]+\.[0-9]+$',t):
          return float(t)
  
      return t
  
  
  def get_model(name):
      return apps.get_model('main', name)
  
  
  class SmartFilter(object):
      SEARCHABLE_RELATIONSHIP = 'ansible_facts'
  
      class BoolOperand(object):
          def __init__(self, t):
              kwargs = dict()
              k, v = self._extract_key_value(t)
              k, v = self._json_path_to_contains(k, v)
  
              Host = get_model('host')
              search_kwargs = self._expand_search(k, v)
              if search_kwargs:
                  kwargs.update(search_kwargs)
                  q = reduce(lambda x, y: x | y, [models.Q(**{u'%s__icontains' % _k:_v}) for _k, _v in kwargs.items()])
                  self.result = Host.objects.filter(q)
              else:
                  # detect loops and restrict access to sensitive fields
                  # this import is intentional here to avoid a circular import
                  from awx.api.filters import FieldLookupBackend
                  FieldLookupBackend().get_field_from_lookup(Host, k)
                  kwargs[k] = v
                  self.result = Host.objects.filter(**kwargs)
  
          def strip_quotes_traditional_logic(self, v):
              if type(v) is str and v.startswith('"') and v.endswith('"'):
                  return v[1:-1]
              return v
  
          def strip_quotes_json_logic(self, v):
              if type(v) is str and v.startswith('"') and v.endswith('"') and v != u'"null"':
                  return v[1:-1]
              return v
  
          '''
          TODO: We should be able to express this in the grammar and let
                pyparsing do the heavy lifting.
          TODO: separate django filter requests from our custom json filter
                request so we don't process the key any. This could be
                accomplished using a whitelist or introspecting the
                relationship refered to to see if it's a jsonb type.
          '''
          def _json_path_to_contains(self, k, v):
              from awx.main.fields import JSONBField  # avoid a circular import
              if not k.startswith(SmartFilter.SEARCHABLE_RELATIONSHIP):
                  v = self.strip_quotes_traditional_logic(v)
                  return (k, v)
  
              for match in JSONBField.get_lookups().keys():
                  match = '__{}'.format(match)
                  if k.endswith(match):
                      if match == '__exact':
                          # appending __exact is basically a no-op, because that's
                          # what the query means if you leave it off
                          k = k[:-len(match)]
                      else:
                          logger.error(
                              'host_filter:{} does not support searching with {}'.format(
                                  SmartFilter.SEARCHABLE_RELATIONSHIP,
                                  match
                              )
                          )
  
              # Strip off leading relationship key
              if k.startswith(SmartFilter.SEARCHABLE_RELATIONSHIP + '__'):
                  strip_len = len(SmartFilter.SEARCHABLE_RELATIONSHIP) + 2
              else:
                  strip_len = len(SmartFilter.SEARCHABLE_RELATIONSHIP)
              k = k[strip_len:]
  
              pieces = k.split(u'__')
  
              assembled_k = u'%s__contains' % (SmartFilter.SEARCHABLE_RELATIONSHIP)
              assembled_v = None
  
              last_v = None
              last_kv = None
  
              for i, piece in enumerate(pieces):
                  new_kv = dict()
                  if piece.endswith(u'[]'):
                      new_v = []
                      new_kv[piece[0:-2]] = new_v
                  else:
                      new_v = dict()
                      new_kv[piece] = new_v
  
                  if last_kv is None:
                      assembled_v = new_kv
                  elif type(last_v) is list:
                      last_v.append(new_kv)
                  elif type(last_v) is dict:
                      last_kv[list(last_kv.keys())[0]] = new_kv
  
                  last_v = new_v
                  last_kv = new_kv
  
              v = self.strip_quotes_json_logic(v)
  
              if type(last_v) is list:
                  last_v.append(v)
              elif type(last_v) is dict:
                  last_kv[list(last_kv.keys())[0]] = v
  
              return (assembled_k, assembled_v)
  
          def _extract_key_value(self, t):
              t_len = len(t)
  
              k = None
              v = None
  
              # key
              # "something"=
              v_offset = 2
              if t_len >= 2 and t[0] == "\"" and t[2] == "\"":
                  k = t[1]
                  v_offset = 4
              # something=
              else:
                  k = t[0]
  
              # value
              # ="something"
              if t_len > (v_offset + 2) and t[v_offset] == "\"" and t[v_offset + 2] == "\"":
                  v = u'"' + str(t[v_offset + 1]) + u'"'
                  #v = t[v_offset + 1]
              # empty ""
              elif t_len > (v_offset + 1):
                  v = u""
              # no ""
              else:
                  v = string_to_type(t[v_offset])
  
              return (k, v)
  
          def _expand_search(self, k, v):
              if 'search' not in k:
                  return None
  
              model, relation = None, None
              if k == 'search':
                  model = get_model('host')
              elif k.endswith('__search'):
                  relation = k.split('__')[0]
                  try:
                      model = get_model(relation)
                  except LookupError:
                      raise ParseException('No related field named %s' % relation)
  
              search_kwargs = {}
              if model is not None:
                  search_fields = get_search_fields(model)
                  for field in search_fields:
                      if relation is not None:
                          k = '{0}__{1}'.format(relation, field)
                      else:
                          k = field
                      search_kwargs[k] = v
              return search_kwargs
  
  
      class BoolBinOp(object):
          def __init__(self, t):
              self.result = None
              i = 2
              while i < len(t[0]):
                  '''
                  Do NOT observe self.result. It will cause the sql query to be executed.
                  We do not want that. We only want to build the query.
                  '''
                  if isinstance(self.result, type(None)):
                      self.result = t[0][0].result
                  right = t[0][i].result
                  self.result = self.execute_logic(self.result, right)
                  i += 2
  
  
      class BoolAnd(BoolBinOp):
          def execute_logic(self, left, right):
              return left & right
  
  
      class BoolOr(BoolBinOp):
          def execute_logic(self, left, right):
              return left | right
  
  
      @classmethod
      def query_from_string(cls, filter_string):
  
          '''
          TODO:
          * handle values with " via: a.b.c.d="hello\"world"
          * handle keys with " via: a.\"b.c="yeah"
          * handle key with __ in it
          '''
          filter_string_raw = filter_string
          filter_string = str(filter_string)
  
          unicode_spaces = list(set(str(c) for c in filter_string if c.isspace()))
          unicode_spaces_other = unicode_spaces + [u'(', u')', u'=', u'"']
          atom = CharsNotIn(unicode_spaces_other)
          atom_inside_quotes = CharsNotIn(u'"')
          atom_quoted = Literal('"') + Optional(atom_inside_quotes) + Literal('"')
          EQUAL = Literal('=')
  
          grammar = ((atom_quoted | atom) + EQUAL + Optional((atom_quoted | atom)))
          grammar.setParseAction(cls.BoolOperand)
  
          boolExpr = infixNotation(grammar, [
              ("and", 2, opAssoc.LEFT, cls.BoolAnd),
              ("or",  2, opAssoc.LEFT, cls.BoolOr),
          ])
  
          try:
              res = boolExpr.parseString('(' + filter_string + ')')
          except ParseException:
              raise RuntimeError(u"Invalid query %s" % filter_string_raw)
  
          if len(res) > 0:
              return res[0].result
  
          raise RuntimeError("Parsing the filter_string %s went terribly wrong" % filter_string)
  