@read_session
def get_suspicious_files(rse_expression, filter=None, **kwargs):
    "\n    Gets a list of replicas from bad_replicas table which are: declared more than <nattempts> times since <younger_than> date,\n    present on the RSE specified by the <rse_expression> and do not have a state in <exclude_states> list.\n    Selected replicas can also be required to be <available_elsewhere> on another RSE than the one declared in bad_replicas table and/or\n    be declared as <is_suspicious> in the bad_replicas table.\n    Keyword Arguments:\n    :param younger_than: Datetime object to select the replicas which were declared since younger_than date. Default value = 10 days ago.\n    :param nattempts: The minimum number of replica appearances in the bad_replica DB table from younger_than date. Default value = 0.\n    :param rse_expression: The RSE expression where the replicas are located.\n    :param filter: Dictionary of attributes by which the RSE results should be filtered. e.g.: {'availability_write': True}\n    :param: exclude_states: List of states which eliminates replicas from search result if any of the states in the list\n                            was declared for a replica since younger_than date. Allowed values\n                            = ['B', 'R', 'D', 'L', 'T', 'S'] (meaning 'BAD', 'RECOVERED', 'DELETED', 'LOST', 'TEMPORARY_UNAVAILABLE', 'SUSPICIOUS').\n    :param: available_elsewhere: If True, only replicas declared in addition as AVAILABLE on another RSE\n                                 than the one in the bad_replicas table will be taken into account. Default value = False.\n    :param: is_suspicious: If True, only replicas declared as SUSPICIOUS in bad replicas table will be taken into account. Default value = False.\n    :param session: The database session in use. Default value = None.\n\n    :returns: a list of replicas:\n    [{'scope': scope, 'name': name, 'rse': rse, 'rse_id': rse_id, cnt': cnt, 'created_at': created_at}, ...]\n    "
    younger_than = kwargs.get('younger_than', (datetime.now() - timedelta(days=10)))
    nattempts = kwargs.get('nattempts', 0)
    session = kwargs.get('session', None)
    exclude_states = kwargs.get('exclude_states', ['B', 'R', 'D'])
    available_elsewhere = kwargs.get('available_elsewhere', False)
    is_suspicious = kwargs.get('is_suspicious', False)
    if (not isinstance(nattempts, int)):
        nattempts = 0
    if (not isinstance(younger_than, datetime)):
        younger_than = (datetime.now() - timedelta(days=10))
    exclude_states_clause = []
    for state in exclude_states:
        exclude_states_clause.append(BadFilesStatus(state))
    bad_replicas_alias = aliased(models.BadReplicas, name='bad_replicas_alias')
    replicas_alias = aliased(models.RSEFileAssociation, name='replicas_alias')
    rse_clause = []
    if rse_expression:
        parsedexp = parse_expression(expression=rse_expression, filter=filter, session=session)
        for rse in parsedexp:
            rse_clause.append((models.RSEFileAssociation.rse_id == rse['id']))
    query = session.query(func.count(), bad_replicas_alias.scope, bad_replicas_alias.name, models.RSEFileAssociation.rse_id, func.min(models.RSEFileAssociation.created_at)).filter((models.RSEFileAssociation.rse_id == bad_replicas_alias.rse_id), (models.RSEFileAssociation.scope == bad_replicas_alias.scope), (models.RSEFileAssociation.name == bad_replicas_alias.name), (bad_replicas_alias.created_at >= younger_than))
    if is_suspicious:
        query.filter((bad_replicas_alias.state == BadFilesStatus.SUSPICIOUS))
    if rse_clause:
        query = query.filter(or_(*rse_clause))
    if available_elsewhere:
        available_replica = exists(select([1]).where(and_((replicas_alias.state == ReplicaState.AVAILABLE), (replicas_alias.scope == bad_replicas_alias.scope), (replicas_alias.name == bad_replicas_alias.name), (replicas_alias.rse_id != bad_replicas_alias.rse_id))))
        query = query.filter(available_replica)
    other_states_present = exists(select([1]).where(and_((models.BadReplicas.scope == bad_replicas_alias.scope), (models.BadReplicas.name == bad_replicas_alias.name), (models.BadReplicas.created_at >= younger_than), (models.BadReplicas.rse_id == bad_replicas_alias.rse_id), models.BadReplicas.state.in_(exclude_states_clause))))
    query = query.filter(not_(other_states_present))
    query_result = query.group_by(models.RSEFileAssociation.rse_id, bad_replicas_alias.scope, bad_replicas_alias.name).having((func.count() > nattempts)).all()
    result = []
    rses = {}
    for (cnt, scope, name, rse_id, created_at) in query_result:
        if (rse_id not in rses):
            rse = get_rse_name(rse_id=rse_id, session=session)
            rses[rse_id] = rse
        result.append({'scope': scope, 'name': name, 'rse': rses[rse_id], 'rse_id': rse_id, 'cnt': cnt, 'created_at': created_at})
    return result
Gets a list of replicas from bad_replicas table which are: declared more than <nattempts> times since <younger_than> date,
present on the RSE specified by the <rse_expression> and do not have a state in <exclude_states> list.
Selected replicas can also be required to be <available_elsewhere> on another RSE than the one declared in bad_replicas table and/or
be declared as <is_suspicious> in the bad_replicas table.
Keyword Arguments:
:param younger_than: Datetime object to select the replicas which were declared since younger_than date. Default value = 10 days ago.
:param nattempts: The minimum number of replica appearances in the bad_replica DB table from younger_than date. Default value = 0.
:param rse_expression: The RSE expression where the replicas are located.
:param filter: Dictionary of attributes by which the RSE results should be filtered. e.g.: {'availability_write': True}
:param: exclude_states: List of states which eliminates replicas from search result if any of the states in the list
                        was declared for a replica since younger_than date. Allowed values
                        = ['B', 'R', 'D', 'L', 'T', 'S'] (meaning 'BAD', 'RECOVERED', 'DELETED', 'LOST', 'TEMPORARY_UNAVAILABLE', 'SUSPICIOUS').
:param: available_elsewhere: If True, only replicas declared in addition as AVAILABLE on another RSE
                             than the one in the bad_replicas table will be taken into account. Default value = False.
:param: is_suspicious: If True, only replicas declared as SUSPICIOUS in bad replicas table will be taken into account. Default value = False.
:param session: The database session in use. Default value = None.

:returns: a list of replicas:
[{'scope': scope, 'name': name, 'rse': rse, 'rse_id': rse_id, cnt': cnt, 'created_at': created_at}, ...]
@read_session
def get_suspicious_files(rse_expression, filter=None, **kwargs):
    "\n    Gets a list of replicas from bad_replicas table which are: declared more than <nattempts> times since <younger_than> date,\n    present on the RSE specified by the <rse_expression> and do not have a state in <exclude_states> list.\n    Selected replicas can also be required to be <available_elsewhere> on another RSE than the one declared in bad_replicas table and/or\n    be declared as <is_suspicious> in the bad_replicas table.\n    Keyword Arguments:\n    :param younger_than: Datetime object to select the replicas which were declared since younger_than date. Default value = 10 days ago.\n    :param nattempts: The minimum number of replica appearances in the bad_replica DB table from younger_than date. Default value = 0.\n    :param rse_expression: The RSE expression where the replicas are located.\n    :param filter: Dictionary of attributes by which the RSE results should be filtered. e.g.: {'availability_write': True}\n    :param: exclude_states: List of states which eliminates replicas from search result if any of the states in the list\n                            was declared for a replica since younger_than date. Allowed values\n                            = ['B', 'R', 'D', 'L', 'T', 'S'] (meaning 'BAD', 'RECOVERED', 'DELETED', 'LOST', 'TEMPORARY_UNAVAILABLE', 'SUSPICIOUS').\n    :param: available_elsewhere: If True, only replicas declared in addition as AVAILABLE on another RSE\n                                 than the one in the bad_replicas table will be taken into account. Default value = False.\n    :param: is_suspicious: If True, only replicas declared as SUSPICIOUS in bad replicas table will be taken into account. Default value = False.\n    :param session: The database session in use. Default value = None.\n\n    :returns: a list of replicas:\n    [{'scope': scope, 'name': name, 'rse': rse, 'rse_id': rse_id, cnt': cnt, 'created_at': created_at}, ...]\n    "
    younger_than = kwargs.get('younger_than', (datetime.now() - timedelta(days=10)))
    nattempts = kwargs.get('nattempts', 0)
    session = kwargs.get('session', None)
    exclude_states = kwargs.get('exclude_states', ['B', 'R', 'D'])
    available_elsewhere = kwargs.get('available_elsewhere', False)
    is_suspicious = kwargs.get('is_suspicious', False)
    if (not isinstance(nattempts, int)):
        nattempts = 0
    if (not isinstance(younger_than, datetime)):
        younger_than = (datetime.now() - timedelta(days=10))
    exclude_states_clause = []
    for state in exclude_states:
        exclude_states_clause.append(BadFilesStatus(state))
    bad_replicas_alias = aliased(models.BadReplicas, name='bad_replicas_alias')
    replicas_alias = aliased(models.RSEFileAssociation, name='replicas_alias')
    rse_clause = []
    if rse_expression:
        parsedexp = parse_expression(expression=rse_expression, filter=filter, session=session)
        for rse in parsedexp:
            rse_clause.append((models.RSEFileAssociation.rse_id == rse['id']))
    query = session.query(func.count(), bad_replicas_alias.scope, bad_replicas_alias.name, models.RSEFileAssociation.rse_id, func.min(models.RSEFileAssociation.created_at)).filter((models.RSEFileAssociation.rse_id == bad_replicas_alias.rse_id), (models.RSEFileAssociation.scope == bad_replicas_alias.scope), (models.RSEFileAssociation.name == bad_replicas_alias.name), (bad_replicas_alias.created_at >= younger_than))
    if is_suspicious:
        query.filter((bad_replicas_alias.state == BadFilesStatus.SUSPICIOUS))
    if rse_clause:
        query = query.filter(or_(*rse_clause))
    if available_elsewhere:
        available_replica = exists(select([1]).where(and_((replicas_alias.state == ReplicaState.AVAILABLE), (replicas_alias.scope == bad_replicas_alias.scope), (replicas_alias.name == bad_replicas_alias.name), (replicas_alias.rse_id != bad_replicas_alias.rse_id))))
        query = query.filter(available_replica)
    other_states_present = exists(select([1]).where(and_((models.BadReplicas.scope == bad_replicas_alias.scope), (models.BadReplicas.name == bad_replicas_alias.name), (models.BadReplicas.created_at >= younger_than), (models.BadReplicas.rse_id == bad_replicas_alias.rse_id), models.BadReplicas.state.in_(exclude_states_clause))))
    query = query.filter(not_(other_states_present))
    query_result = query.group_by(models.RSEFileAssociation.rse_id, bad_replicas_alias.scope, bad_replicas_alias.name).having((func.count() > nattempts)).all()
    result = []
    rses = {}
    for (cnt, scope, name, rse_id, created_at) in query_result:
        if (rse_id not in rses):
            rse = get_rse_name(rse_id=rse_id, session=session)
            rses[rse_id] = rse
        result.append({'scope': scope, 'name': name, 'rse': rses[rse_id], 'rse_id': rse_id, 'cnt': cnt, 'created_at': created_at})
    return result