Passed
Pull Request — master (#496)
by
unknown
02:13
created

AnnifBackend._validate_input_limit()   A

Complexity

Conditions 2

Size

Total Lines 7
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 6
dl 0
loc 7
rs 10
c 0
b 0
f 0
cc 2
nop 2
1
"""Common functionality for backends."""
2
3
import abc
4
import os.path
5
from datetime import datetime, timezone
6
from glob import glob
7
from annif import logger
8
9
10
class AnnifBackend(metaclass=abc.ABCMeta):
11
    """Base class for Annif backends that perform analysis. The
12
    non-implemented methods should be overridden in subclasses."""
13
14
    name = None
15
    needs_subject_index = False
16
17
    DEFAULT_PARAMETERS = {'limit': 100}
18
19
    def __init__(self, backend_id, config_params, project):
20
        """Initialize backend with specific parameters. The
21
        parameters are a dict. Keys and values depend on the specific
22
        backend type."""
23
        self.backend_id = backend_id
24
        self.config_params = config_params
25
        self.project = project
26
        self.datadir = project.datadir
27
28
    def default_params(self):
29
        return self.DEFAULT_PARAMETERS
30
31
    @property
32
    def params(self):
33
        params = {}
34
        params.update(self.default_params())
35
        params.update(self.config_params)
36
        return params
37
38
    @property
39
    def is_trained(self):
40
        return bool(glob(os.path.join(self.datadir, '*')))
41
42
    @property
43
    def modification_time(self):
44
        mtimes = [datetime.utcfromtimestamp(os.path.getmtime(p))
45
                  for p in glob(os.path.join(self.datadir, '*'))]
46
        most_recent = max(mtimes, default=None)
47
        if most_recent is None:
48
            return None
49
        return most_recent.replace(tzinfo=timezone.utc)
50
51
    def _get_backend_params(self, params):
52
        backend_params = dict(self.params)
53
        if params is not None:
54
            backend_params.update(params)
55
        return backend_params
56
57
    def _train(self, corpus, params):
58
        """This method can be overridden by backends. It implements
59
        the train functionality, with pre-processed parameters."""
60
        pass  # default is to do nothing, subclasses may override
61
62
    def train(self, corpus, params=None):
63
        """Train the model on the given document or subject corpus."""
64
        beparams = self._get_backend_params(params)
65
        return self._train(corpus, params=beparams)
66
67
    def initialize(self):
68
        """This method can be overridden by backends. It should cause the
69
        backend to pre-load all data it needs during operation."""
70
        pass
71
72
    @abc.abstractmethod
73
    def _suggest(self, text, params):
74
        """This method should implemented by backends. It implements
75
        the suggest functionality, with pre-processed parameters."""
76
        pass  # pragma: no cover
77
78
    def suggest(self, text, params=None):
79
        """Suggest subjects for the input text and return a list of subjects
80
        represented as a list of SubjectSuggestion objects."""
81
        beparams = self._get_backend_params(params)
82
        self.initialize()
83
        return self._suggest(text, params=beparams)
84
85
    def debug(self, message):
86
        """Log a debug message from this backend"""
87
        logger.debug("Backend {}: {}".format(self.backend_id, message))
88
89
    def info(self, message):
90
        """Log an info message from this backend"""
91
        logger.info("Backend {}: {}".format(self.backend_id, message))
92
93
    def warning(self, message):
94
        """Log a warning message from this backend"""
95
        logger.warning("Backend {}: {}".format(self.backend_id, message))
96
97
98
class AnnifLearningBackend(AnnifBackend):
99
    """Base class for Annif backends that can perform online learning"""
100
101
    @abc.abstractmethod
102
    def _learn(self, corpus, params):
103
        """This method should implemented by backends. It implements the learn
104
        functionality, with pre-processed parameters."""
105
        pass  # pragma: no cover
106
107
    def learn(self, corpus, params=None):
108
        """Further train the model on the given document or subject corpus."""
109
        beparams = self._get_backend_params(params)
110
        return self._learn(corpus, params=beparams)
111