<commit_before>from __future__ import absolute_import, print_function, unicode_literals
from builtins import dict, str
import logging
import indra.statements as ist

logger = logging.getLogger(__name__)


class EnglishAssembler(object):
    """This assembler generates English sentences from INDRA Statements.

    Parameters
    ----------
    stmts : Optional[list[indra.statements.Statement]]
        A list of INDRA Statements to be added to the assembler.

    Attributes
    ----------
    statements : list[indra.statements.Statement]
        A list of INDRA Statements to assemble.
    model : str
        The assembled sentences as a single string.
    """
    def __init__(self, stmts=None):
        if stmts is None:
            self.statements = []
        else:
            self.statements = stmts
        self.model = None

    def add_statements(self, stmts):
        """Add INDRA Statements to the assembler's list of statements.

        Parameters
        ----------
        stmts : list[indra.statements.Statement]
            A list of :py:class:`indra.statements.Statement`
            to be added to the statement list of the assembler.
        """
        self.statements += stmts

    def make_model(self):
        """Assemble text from the set of collected INDRA Statements.

        Returns
        -------
        stmt_strs : str
            Return the assembled text as unicode string. By default, the text
            is a single string consisting of one or more sentences with
            periods at the end.
        """
        stmt_strs = []
        for stmt in self.statements:
            if isinstance(stmt, ist.Modification):
                stmt_strs.append(_assemble_modification(stmt))
            elif isinstance(stmt, ist.Autophosphorylation):
                stmt_strs.append(_assemble_autophosphorylation(stmt))
            elif isinstance(stmt, ist.Association):
                stmt_strs.append(_assemble_association(stmt))
            elif isinstance(stmt, ist.Complex):
                stmt_strs.append(_assemble_complex(stmt))
            elif isinstance(stmt, ist.Influence):
                stmt_strs.append(_assemble_influence(stmt))
            elif isinstance(stmt, ist.RegulateActivity):
                stmt_strs.append(_assemble_regulate_activity(stmt))
            elif isinstance(stmt, ist.RegulateAmount):
                stmt_strs.append(_assemble_regulate_amount(stmt))
            elif isinstance(stmt, ist.ActiveForm):
                stmt_strs.append(_assemble_activeform(stmt))
            elif isinstance(stmt, ist.Translocation):
                stmt_strs.append(_assemble_translocation(stmt))
            elif isinstance(stmt, ist.Gef):
                stmt_strs.append(_assemble_gef(stmt))
            elif isinstance(stmt, ist.Gap):
                stmt_strs.append(_assemble_gap(stmt))
            elif isinstance(stmt, ist.Conversion):
                stmt_strs.append(_assemble_conversion(stmt))
            else:
                logger.warning('Unhandled statement type: %s.' % type(stmt))
        if stmt_strs:
            return ' '.join(stmt_strs)
        else:
            return ''


def _assemble_agent_str(agent):
    """Assemble an Agent object to text."""
    agent_str = agent.name

    # Only do the more detailed assembly for molecular agents
    if not isinstance(agent, ist.Agent):
        return agent_str

    # Handle mutation conditions
    if agent.mutations:
        is_generic = False
        mut_strs = []
        for mut in agent.mutations:
            res_to = mut.residue_to if mut.residue_to else ''
            res_from = mut.residue_from if mut.residue_from else ''
            pos = mut.position if mut.position else ''
            mut_str = '%s%s%s' % (res_from, pos, res_to)
            # If this is the only mutation and there are no details
            # then this is a generic mutant
            if not mut_str and len(agent.mutations) == 1:
                is_generic = True
                break
            mut_strs.append(mut_str)
        if is_generic:
            agent_str = 'mutated ' + agent_str
        else:
            mut_strs = '/'.join(mut_strs)
            agent_str = '%s-%s' % (agent_str, mut_strs)

    # Handle location
    if agent.location is not None:
        agent_str += ' in the ' + agent.location

    if not agent.mods and not agent.bound_conditions and not agent.activity:
        return agent_str

    # Handle bound conditions
    bound_to = [bc.agent.name for bc in
                agent.bound_conditions if bc.is_bound]
    not_bound_to = [bc.agent.name for bc in
                agent.bound_conditions if not bc.is_bound]
    if bound_to:
        agent_str += ' bound to ' + _join_list(bound_to)
        if not_bound_to:
            agent_str += ' and not bound to ' +\
                _join_list(not_bound_to)
    else:
        if not_bound_to:
            agent_str += ' not bound to ' +\
                _join_list(not_bound_to)

    # Handle modification conditions
    if agent.mods:
        # Special case
        if len(agent.mods) == 1 and agent.mods[0].position is None:
            prefix = _mod_state_str(agent.mods[0].mod_type)
            if agent.mods[0].residue is not None:
                residue_str =\
                    ist.amino_acids[agent.mods[0].residue]['full_name']
                prefix = residue_str + '-' + prefix
            agent_str = prefix + ' ' + agent_str
        else:
            if agent.bound_conditions:
                agent_str += ' and'
            agent_str += ' %s on ' % _mod_state_str(agent.mods[0].mod_type)
            mod_lst = []
            for m in agent.mods:
                if m.position is None:
                    if m.residue is not None:
                        residue_str =\
                            ist.amino_acids[m.residue]['full_name']
                        mod_lst.append(residue_str)
                    else:
                        mod_lst.append('an unknown residue')
                elif m.position is not None and m.residue is None:
                    mod_lst.append('amino acid %s' % m.position)
                else:
                    mod_lst.append(m.residue + m.position)
            agent_str += _join_list(mod_lst)


    # Handle activity conditions
    if agent.activity is not None:
        # Get the modifier specific to the activity type, if any
        pre_prefix = \
            activity_type_prefix.get(agent.activity.activity_type, '')
        if agent.activity.is_active:
            prefix = pre_prefix + 'active'
        else:
            # See if there is a special override for the inactive form
            if agent.activity.activity_type in inactivity_type_prefix_override:
                pre_prefix = inactivity_type_prefix_override[
                    agent.activity.activity_type]
            prefix = pre_prefix + 'inactive'
        agent_str = prefix + ' ' + agent_str

    return agent_str


def _join_list(lst, oxford=False):
    """Join a list of words in a gramatically correct way."""
    if len(lst) > 2:
        s = ', '.join(lst[:-1])
        if oxford:
            s += ','
        s += ' and ' + lst[-1]
    elif len(lst) == 2:
        s = lst[0] + ' and ' + lst[1]
    elif len(lst) == 1:
        s = lst[0]
    else:<commit_msg>Add English join API function<commit_after>from __future__ import absolute_import, print_function, unicode_literals
from builtins import dict, str
import logging
import indra.statements as ist

logger = logging.getLogger(__name__)


class EnglishAssembler(object):
    """This assembler generates English sentences from INDRA Statements.

    Parameters
    ----------
    stmts : Optional[list[indra.statements.Statement]]
        A list of INDRA Statements to be added to the assembler.

    Attributes
    ----------
    statements : list[indra.statements.Statement]
        A list of INDRA Statements to assemble.
    model : str
        The assembled sentences as a single string.
    """
    def __init__(self, stmts=None):
        if stmts is None:
            self.statements = []
        else:
            self.statements = stmts
        self.model = None

    def add_statements(self, stmts):
        """Add INDRA Statements to the assembler's list of statements.

        Parameters
        ----------
        stmts : list[indra.statements.Statement]
            A list of :py:class:`indra.statements.Statement`
            to be added to the statement list of the assembler.
        """
        self.statements += stmts

    def make_model(self):
        """Assemble text from the set of collected INDRA Statements.

        Returns
        -------
        stmt_strs : str
            Return the assembled text as unicode string. By default, the text
            is a single string consisting of one or more sentences with
            periods at the end.
        """
        stmt_strs = []
        for stmt in self.statements:
            if isinstance(stmt, ist.Modification):
                stmt_strs.append(_assemble_modification(stmt))
            elif isinstance(stmt, ist.Autophosphorylation):
                stmt_strs.append(_assemble_autophosphorylation(stmt))
            elif isinstance(stmt, ist.Association):
                stmt_strs.append(_assemble_association(stmt))
            elif isinstance(stmt, ist.Complex):
                stmt_strs.append(_assemble_complex(stmt))
            elif isinstance(stmt, ist.Influence):
                stmt_strs.append(_assemble_influence(stmt))
            elif isinstance(stmt, ist.RegulateActivity):
                stmt_strs.append(_assemble_regulate_activity(stmt))
            elif isinstance(stmt, ist.RegulateAmount):
                stmt_strs.append(_assemble_regulate_amount(stmt))
            elif isinstance(stmt, ist.ActiveForm):
                stmt_strs.append(_assemble_activeform(stmt))
            elif isinstance(stmt, ist.Translocation):
                stmt_strs.append(_assemble_translocation(stmt))
            elif isinstance(stmt, ist.Gef):
                stmt_strs.append(_assemble_gef(stmt))
            elif isinstance(stmt, ist.Gap):
                stmt_strs.append(_assemble_gap(stmt))
            elif isinstance(stmt, ist.Conversion):
                stmt_strs.append(_assemble_conversion(stmt))
            else:
                logger.warning('Unhandled statement type: %s.' % type(stmt))
        if stmt_strs:
            return ' '.join(stmt_strs)
        else:
            return ''


def _assemble_agent_str(agent):
    """Assemble an Agent object to text."""
    agent_str = agent.name

    # Only do the more detailed assembly for molecular agents
    if not isinstance(agent, ist.Agent):
        return agent_str

    # Handle mutation conditions
    if agent.mutations:
        is_generic = False
        mut_strs = []
        for mut in agent.mutations:
            res_to = mut.residue_to if mut.residue_to else ''
            res_from = mut.residue_from if mut.residue_from else ''
            pos = mut.position if mut.position else ''
            mut_str = '%s%s%s' % (res_from, pos, res_to)
            # If this is the only mutation and there are no details
            # then this is a generic mutant
            if not mut_str and len(agent.mutations) == 1:
                is_generic = True
                break
            mut_strs.append(mut_str)
        if is_generic:
            agent_str = 'mutated ' + agent_str
        else:
            mut_strs = '/'.join(mut_strs)
            agent_str = '%s-%s' % (agent_str, mut_strs)

    # Handle location
    if agent.location is not None:
        agent_str += ' in the ' + agent.location

    if not agent.mods and not agent.bound_conditions and not agent.activity:
        return agent_str

    # Handle bound conditions
    bound_to = [bc.agent.name for bc in
                agent.bound_conditions if bc.is_bound]
    not_bound_to = [bc.agent.name for bc in
                agent.bound_conditions if not bc.is_bound]
    if bound_to:
        agent_str += ' bound to ' + _join_list(bound_to)
        if not_bound_to:
            agent_str += ' and not bound to ' +\
                _join_list(not_bound_to)
    else:
        if not_bound_to:
            agent_str += ' not bound to ' +\
                _join_list(not_bound_to)

    # Handle modification conditions
    if agent.mods:
        # Special case
        if len(agent.mods) == 1 and agent.mods[0].position is None:
            prefix = _mod_state_str(agent.mods[0].mod_type)
            if agent.mods[0].residue is not None:
                residue_str =\
                    ist.amino_acids[agent.mods[0].residue]['full_name']
                prefix = residue_str + '-' + prefix
            agent_str = prefix + ' ' + agent_str
        else:
            if agent.bound_conditions:
                agent_str += ' and'
            agent_str += ' %s on ' % _mod_state_str(agent.mods[0].mod_type)
            mod_lst = []
            for m in agent.mods:
                if m.position is None:
                    if m.residue is not None:
                        residue_str =\
                            ist.amino_acids[m.residue]['full_name']
                        mod_lst.append(residue_str)
                    else:
                        mod_lst.append('an unknown residue')
                elif m.position is not None and m.residue is None:
                    mod_lst.append('amino acid %s' % m.position)
                else:
                    mod_lst.append(m.residue + m.position)
            agent_str += _join_list(mod_lst)


    # Handle activity conditions
    if agent.activity is not None:
        # Get the modifier specific to the activity type, if any
        pre_prefix = \
            activity_type_prefix.get(agent.activity.activity_type, '')
        if agent.activity.is_active:
            prefix = pre_prefix + 'active'
        else:
            # See if there is a special override for the inactive form
            if agent.activity.activity_type in inactivity_type_prefix_override:
                pre_prefix = inactivity_type_prefix_override[
                    agent.activity.activity_type]
            prefix = pre_prefix + 'inactive'
        agent_str = prefix + ' ' + agent_str

    return agent_str


def english_join(lst):
    """Join a list of strings according to English grammar.

    Parameters
    ----------
    lst : list of str
        A list of strings to join.

    Returns
    -------
    str
        A string which describes the list of elements, e.g.,
        "apples, pears, and bananas".
    """
    return _join_list(lst, oxford=True)


def _join_list(lst, oxford=True):
    """Join a list of words in a gramatically correct way."""
    if len(lst) > 2:
        s = ', '.join(lst[:-1])
        if oxford:
            s += ','
        s += ' and ' + lst[-1]
    elif len(lst) == 2:
        s = lst[0] + ' and ' + lst[1]
    elif len(lst) == 1:
        s = lst[0]
    else:
{'fraction_non_alphanumeric': 0.08891563043187592, 'fraction_numerical': 0.0020056157240272766, 'mean_word_length': 1.8283229343921346, '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': '350754', 'n_tokens_mistral': 4358, 'n_tokens_neox': 4113, 'n_words': 1117}