Example #1
0
    def __init__(self, config, pattern_assistant):
        self.config = config
        self.pattern_assistant = pattern_assistant

        self._parsers = {}
        self._constraint_base = {}
        self._constraint_links = ConstraintLinksBase()
        self.effect_id = None
Example #2
0
 def setUp(self):
     self.links = [
         (1, 10, 100),
         (1, 20, 200),
         (2, 10, 100),
         (2, 10, 200),
         (2, 20, 100),
         (2, 20, 200),
     ]
     self.constraint_links = ConstraintLinksBase(self.links)
Example #3
0
    def __init__(self, config, pattern_assistant):
        self.config = config
        self.pattern_assistant = pattern_assistant

        self._parsers = {}
        self._constraint_base = {}
        self._constraint_links = ConstraintLinksBase()
        self.effect_id = None
 def setUp(self):
     self.links = [
         (1, 10, 100),
         (1, 20, 200),
         (2, 10, 100),
         (2, 10, 200),
         (2, 20, 100),
         (2, 20, 200),
     ]
     self.constraint_links = ConstraintLinksBase(self.links)
Example #5
0
class Teacher(object):
    """
    Enable teaching new rule. One Teacher per one entering rule.
    :type pattern_assistant: AbstractAssistant
    :type _parsers: dict[int, TeacherParser]
    :type _constraint_base: dict[int, AbstractConstraint]
    :param _constraint_links: Keeps links between constraints and groups.
                              Link between constraint C and group G exists
                              if C describes relation between G and other groups.
    :type _constraint_links: ConstraintLinksBase
    """
    def __init__(self, config, pattern_assistant):
        self.config = config
        self.pattern_assistant = pattern_assistant

        self._parsers = {}
        self._constraint_base = {}
        self._constraint_links = ConstraintLinksBase()
        self.effect_id = None

    def add_line(self, line_id, line_object, effect=False):
        """
        Adds new line to rule.
        If line_id already exists, old line is overwritten by new line
        and all constraints related to old line are removed.
        """
        if line_id in six.iterkeys(self._parsers):
            self.remove_line(line_id)
        if effect:
            self.effect_id = line_id
        self._add_default_parser(line_id, line_object)

    def _get_names_blacklist(self):
        return [parser.name for parser in six.itervalues(self._parsers)]

    def _add_default_parser(self, line_id, line_object):
        self.pattern_assistant.add_line(line_id, line_object)

        default_pattern_match = self.pattern_assistant.get_pattern_match(
            line_id)
        default_pattern = default_pattern_match.pattern

        default_name = self.config.propose_parser_name(
            line_object.line_content, default_pattern,
            self._get_names_blacklist())
        default_log_type_name = None

        new_teacher_parser = TeacherParser(line_object, default_name,
                                           default_log_type_name)
        self._parsers[line_id] = new_teacher_parser

    def remove_line(self, line_id):
        """
        Removes line from rule.
        Assumption: line with line_id exists in rule.
        Removes also all constraints related to this line.
        """

        self._remove_constraints_by_line(line_id)
        self.pattern_assistant.remove_line(line_id)
        if line_id == self.effect_id:
            self.effect_id = None
        del self._parsers[line_id]

    def update_pattern(self, line_id, pattern):
        """
        Loads text pattern proposed by user, verifies if it matches line text.
        Removes constraints related with updating line
        TODO: Update related constraints rather than remove.
        """
        self.pattern_assistant.update_by_pattern(line_id, pattern)
        self._remove_constraints_by_line(line_id)

    def guess_patterns(self, line_id):
        """
        Returns list of guessed patterns for a line.
        """
        return self.pattern_assistant.guess_pattern_matches(line_id)

    def choose_guessed_pattern(self, line_id, pattern_id):
        self.pattern_assistant.update_by_guessed_pattern_match(
            line_id, pattern_id)

    def set_pattern_name(self, line_id, name):
        self._parsers[line_id].name = name

    def set_converter(self, line_id, group_no, converter):
        # Assumption: converter is one of valid converters
        self.pattern_assistant.set_converter(line_id, group_no, converter)

    def set_primary_key(self, line_id, group_numbers):
        # Assumption: group_numbers is list of integers
        self.pattern_assistant.set_primary_key(line_id, group_numbers)

    def set_log_type(self, line_id, log_type):
        # Assumption: log_type is accepted by Config
        self._parsers[line_id].log_type = log_type

    def register_constraint(self, constraint_id, constraint):
        """
        Adds new constraint to rule.
        If constraint_id already exists, constraint with this constraint_id
        is overwritten by new constraint
        """
        if constraint_id in six.iterkeys(self._constraint_base):
            self.remove_constraint(constraint_id)

        self._constraint_base[constraint_id] = constraint
        new_constraint_links = [(line_id, group_no, constraint_id)
                                for (line_id, group_no) in constraint.groups]
        self._constraint_links.add_links(new_constraint_links)

    def remove_constraint(self, constraint_id):
        """
        Removes constraint from rule.
        Assumption: Constraint already exists in rule.
        """
        self._constraint_links.remove_links_by_constraint(constraint_id)
        del self._constraint_base[constraint_id]

    def _remove_constraints_by_line(self, line_id):
        constraints_to_remove = self._constraint_links.remove_links_by_line(
            line_id)
        for constraint_id in constraints_to_remove:
            self.remove_constraint(constraint_id)

    def _remove_constraint_by_group(self, line_id, group_number):
        constraints_to_remove = self._constraint_links.remove_links_by_group(
            line_id, group_number)
        for constraint_id in constraints_to_remove:
            self.remove_constraint(constraint_id)

    def set_causes_relation(self, relation):
        """
        Determines which combinations of causes can cause effect.
        :param relation: kind of sentence made of AND, OR, brackets and cause symbols.
        """
        pass

    def _rule_problems(self):
        problems = []
        if self.effect_id is None:
            problems.append(NoEffectParserProblem())
        if len(self._parsers) < 2:
            problems.append(ParserCountProblem())
        return problems

    def _parser_problems(self):
        problems = {}
        names_blacklist = self._get_names_blacklist()
        for parser_id, parser in six.iteritems(self._parsers):
            parser_problems = []
            parser_problems.extend(
                parser.validate_name(self.config, names_blacklist))
            parser_problems.extend(parser.validate_log_type())
            parser_problems.extend(self.pattern_assistant.validate(parser_id))
            problems[parser_id] = parser_problems
        return problems

    def _constraint_problems(self):
        return dict(
            (constraint_id, constraint.validate())
            for constraint_id, constraint in six.iteritems(self._constraint_base)
        )  # yapf: disable

    def validate(self):
        """
        Verifies if Rule is ready to save.
        """

        return ValidationResult(self._rule_problems(), self._parser_problems(),
                                self._constraint_problems())

    def _prepare_user_parser(self, line_id):
        """
        :type pattern_match: PatternMatch
        """
        pattern_match = self.pattern_assistant.get_pattern_match(line_id)
        teacher_parser = self._parsers[line_id]
        pattern_type = self.pattern_assistant.TYPE
        return UserParserIntent(
            pattern_type, teacher_parser.name, pattern_match.pattern, teacher_parser.log_type,
            pattern_match.primary_key, pattern_match.param_groups,
            teacher_parser.line.line_content, teacher_parser.line.offset,
            teacher_parser.line.line_source, line_id
        )  # yapf: disable

    def get_rule(self):
        """
        Creates rule for Front that will be shown to user
        """
        user_parsers = dict(
            (line_id, self._prepare_user_parser(line_id)) for line_id in six.iterkeys(self._parsers)
        )  # yapf: disable
        user_constraints = [
            constraint.convert_to_user_constraint_intent(constraint_id) for
            constraint_id, constraint in six.iteritems(self._constraint_base)
        ]
        return UserRuleIntent(self.effect_id, user_parsers, user_constraints)

    def save(self):
        """
        Verifies text patterns and constraints. If they meet all requirements, saves Rule.
        """
        validation_result = self.validate()
        if validation_result.is_acceptable():
            self.config.add_rule(self.get_rule())
        else:
            return validation_result
class TestBasic(TestCase):
    def setUp(self):
        self.links = [
            (1, 10, 100),
            (1, 20, 200),
            (2, 10, 100),
            (2, 10, 200),
            (2, 20, 100),
            (2, 20, 200),
        ]
        self.constraint_links = ConstraintLinksBase(self.links)

    def test_distinct_constraint_ids(self):
        assert set(self.constraint_links.distinct_constraint_ids()) == set([100, 200])

    def test_add_links(self):
        new_links = [(2, 20, 200), (3, 30, 300)]
        self.constraint_links.add_links(new_links)
        constr_links = self.constraint_links.get_links()
        assert len(self.links) + 1 == len(constr_links)
        assert set(constr_links) == set(
            [
                (1, 10, 100),
                (1, 20, 200),
                (2, 10, 100),
                (2, 10, 200),
                (2, 20, 100),
                (2, 20, 200),
                (3, 30, 300),
            ]
        )

    def test_remove_by_line(self):
        self.constraint_links.remove_links_by_line(1)
        assert set(self.constraint_links.get_links()) == set(
            [
                (2, 10, 100),
                (2, 10, 200),
                (2, 20, 100),
                (2, 20, 200),
            ]
        )

    def test_remove_by_group(self):
        self.constraint_links.remove_links_by_group(2, 20)
        assert set(self.constraint_links.get_links()) == set(
            [
                (1, 10, 100),
                (1, 20, 200),
                (2, 10, 100),
                (2, 10, 200),
            ]
        )

    def test_remove_by_constraint(self):
        self.constraint_links.remove_links_by_constraint(100)
        assert set(self.constraint_links.get_links()) == set(
            [
                (1, 20, 200),
                (2, 10, 200),
                (2, 20, 200),
            ]
        )
Example #7
0
class TestBasic(TestCase):
    def setUp(self):
        self.links = [
            (1, 10, 100),
            (1, 20, 200),
            (2, 10, 100),
            (2, 10, 200),
            (2, 20, 100),
            (2, 20, 200),
        ]
        self.constraint_links = ConstraintLinksBase(self.links)

    def test_distinct_constraint_ids(self):
        assert set(self.constraint_links.distinct_constraint_ids()) == set(
            [100, 200])

    def test_add_links(self):
        new_links = [(2, 20, 200), (3, 30, 300)]
        self.constraint_links.add_links(new_links)
        constr_links = self.constraint_links.get_links()
        assert len(self.links) + 1 == len(constr_links)
        assert set(constr_links) == set([
            (1, 10, 100),
            (1, 20, 200),
            (2, 10, 100),
            (2, 10, 200),
            (2, 20, 100),
            (2, 20, 200),
            (3, 30, 300),
        ])

    def test_remove_by_line(self):
        self.constraint_links.remove_links_by_line(1)
        assert set(self.constraint_links.get_links()) == set([
            (2, 10, 100),
            (2, 10, 200),
            (2, 20, 100),
            (2, 20, 200),
        ])

    def test_remove_by_group(self):
        self.constraint_links.remove_links_by_group(2, 20)
        assert set(self.constraint_links.get_links()) == set([
            (1, 10, 100),
            (1, 20, 200),
            (2, 10, 100),
            (2, 10, 200),
        ])

    def test_remove_by_constraint(self):
        self.constraint_links.remove_links_by_constraint(100)
        assert set(self.constraint_links.get_links()) == set([
            (1, 20, 200),
            (2, 10, 200),
            (2, 20, 200),
        ])
Example #8
0
class Teacher(object):
    """
    Enable teaching new rule. One Teacher per one entering rule.
    :type pattern_assistant: AbstractAssistant
    :type _parsers: dict[int, TeacherParser]
    :type _constraint_base: dict[int, AbstractConstraint]
    :param _constraint_links: Keeps links between constraints and groups.
                              Link between constraint C and group G exists
                              if C describes relation between G and other groups.
    :type _constraint_links: ConstraintLinksBase
    """

    def __init__(self, config, pattern_assistant):
        self.config = config
        self.pattern_assistant = pattern_assistant

        self._parsers = {}
        self._constraint_base = {}
        self._constraint_links = ConstraintLinksBase()
        self.effect_id = None

    def add_line(self, line_id, line_object, effect=False):
        """
        Adds new line to rule.
        If line_id already exists, old line is overwritten by new line
        and all constraints related to old line are removed.
        """
        if line_id in six.iterkeys(self._parsers):
            self.remove_line(line_id)
        if effect:
            self.effect_id = line_id
        self._add_default_parser(line_id, line_object)

    def _get_names_blacklist(self):
        return [parser.name for parser in six.itervalues(self._parsers)]

    def _add_default_parser(self, line_id, line_object):
        self.pattern_assistant.add_line(line_id, line_object)

        default_pattern_match = self.pattern_assistant.get_pattern_match(line_id)
        default_pattern = default_pattern_match.pattern

        default_name = self.config.propose_parser_name(
            line_object.line_content, default_pattern, self._get_names_blacklist()
        )
        default_log_type_name = None

        new_teacher_parser = TeacherParser(line_object, default_name, default_log_type_name)
        self._parsers[line_id] = new_teacher_parser

    def remove_line(self, line_id):
        """
        Removes line from rule.
        Assumption: line with line_id exists in rule.
        Removes also all constraints related to this line.
        """

        self._remove_constraints_by_line(line_id)
        self.pattern_assistant.remove_line(line_id)
        if line_id == self.effect_id:
            self.effect_id = None
        del self._parsers[line_id]

    def update_pattern(self, line_id, pattern):
        """
        Loads text pattern proposed by user, verifies if it matches line text.
        Removes constraints related with updating line
        TODO: Update related constraints rather than remove.
        """
        self.pattern_assistant.update_by_pattern(line_id, pattern)
        self._remove_constraints_by_line(line_id)

    def guess_patterns(self, line_id):
        """
        Returns list of guessed patterns for a line.
        """
        return self.pattern_assistant.guess_pattern_matches(line_id)

    def choose_guessed_pattern(self, line_id, pattern_id):
        self.pattern_assistant.update_by_guessed_pattern_match(line_id, pattern_id)

    def set_pattern_name(self, line_id, name):
        self._parsers[line_id].name = name

    def set_converter(self, line_id, group_no, converter):
        # Assumption: converter is one of valid converters
        self.pattern_assistant.set_converter(line_id, group_no, converter)

    def set_primary_key(self, line_id, group_numbers):
        # Assumption: group_numbers is list of integers
        self.pattern_assistant.set_primary_key(line_id, group_numbers)

    def set_log_type(self, line_id, log_type):
        # Assumption: log_type is accepted by Config
        self._parsers[line_id].log_type = log_type

    def register_constraint(self, constraint_id, constraint):
        """
        Adds new constraint to rule.
        If constraint_id already exists, constraint with this constraint_id
        is overwritten by new constraint
        """
        if constraint_id in six.iterkeys(self._constraint_base):
            self.remove_constraint(constraint_id)

        self._constraint_base[constraint_id] = constraint
        new_constraint_links = [
            (line_id, group_no, constraint_id) for (line_id, group_no) in constraint.groups
        ]
        self._constraint_links.add_links(new_constraint_links)

    def remove_constraint(self, constraint_id):
        """
        Removes constraint from rule.
        Assumption: Constraint already exists in rule.
        """
        self._constraint_links.remove_links_by_constraint(constraint_id)
        del self._constraint_base[constraint_id]

    def _remove_constraints_by_line(self, line_id):
        constraints_to_remove = self._constraint_links.remove_links_by_line(line_id)
        for constraint_id in constraints_to_remove:
            self.remove_constraint(constraint_id)

    def _remove_constraint_by_group(self, line_id, group_number):
        constraints_to_remove = self._constraint_links.remove_links_by_group(line_id, group_number)
        for constraint_id in constraints_to_remove:
            self.remove_constraint(constraint_id)

    def set_causes_relation(self, relation):
        """
        Determines which combinations of causes can cause effect.
        :param relation: kind of sentence made of AND, OR, brackets and cause symbols.
        """
        pass

    def _rule_problems(self):
        problems = []
        if self.effect_id is None:
            problems.append(NoEffectParserProblem())
        if len(self._parsers) < 2:
            problems.append(ParserCountProblem())
        return problems

    def _parser_problems(self):
        problems = {}
        names_blacklist = self._get_names_blacklist()
        for parser_id, parser in six.iteritems(self._parsers):
            parser_problems = []
            parser_problems.extend(parser.validate_name(self.config, names_blacklist))
            parser_problems.extend(parser.validate_log_type())
            parser_problems.extend(self.pattern_assistant.validate(parser_id))
            problems[parser_id] = parser_problems
        return problems

    def _constraint_problems(self):
        return dict(
            (constraint_id, constraint.validate())
            for constraint_id, constraint in six.iteritems(self._constraint_base)
        )  # yapf: disable

    def validate(self):
        """
        Verifies if Rule is ready to save.
        """

        return ValidationResult(
            self._rule_problems(), self._parser_problems(), self._constraint_problems()
        )

    def _prepare_user_parser(self, line_id):
        """
        :type pattern_match: PatternMatch
        """
        pattern_match = self.pattern_assistant.get_pattern_match(line_id)
        teacher_parser = self._parsers[line_id]
        pattern_type = self.pattern_assistant.TYPE
        return UserParserIntent(
            pattern_type, teacher_parser.name, pattern_match.pattern, teacher_parser.log_type,
            pattern_match.primary_key, pattern_match.param_groups,
            teacher_parser.line.line_content, teacher_parser.line.offset,
            teacher_parser.line.line_source, line_id
        )  # yapf: disable

    def get_rule(self):
        """
        Creates rule for Front that will be shown to user
        """
        user_parsers = dict(
            (line_id, self._prepare_user_parser(line_id)) for line_id in six.iterkeys(self._parsers)
        )  # yapf: disable
        user_constraints = [
            constraint.convert_to_user_constraint_intent(constraint_id)
            for constraint_id, constraint in six.iteritems(self._constraint_base)
        ]
        return UserRuleIntent(self.effect_id, user_parsers, user_constraints)

    def save(self):
        """
        Verifies text patterns and constraints. If they meet all requirements, saves Rule.
        """
        validation_result = self.validate()
        if validation_result.is_acceptable():
            self.config.add_rule(self.get_rule())
        else:
            return validation_result