Passed
Pull Request — master (#610)
by Osma
06:08
created

annif.registry.AnnifRegistry.get_vocab()   A

Complexity

Conditions 4

Size

Total Lines 16
Code Lines 13

Duplication

Lines 16
Ratio 100 %

Importance

Changes 0
Metric Value
cc 4
eloc 13
nop 3
dl 16
loc 16
rs 9.75
c 0
b 0
f 0
1
"""Registry that keeps track of Annif projects"""
2
3
import collections
4
import re
5
from flask import current_app
6
import annif
7
from annif.config import parse_config
8
from annif.project import Access, AnnifProject
9
from annif.vocab import AnnifVocabulary
10
from annif.util import parse_args
11
12
logger = annif.logger
13
14
15 View Code Duplication
class AnnifRegistry:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
16
    """Class that keeps track of the Annif projects and vocabularies"""
17
18
    # Note: The individual projects and vocabularies are stored in shared
19
    # static variables, keyed by the "registry ID" which is unique to the
20
    # registry instance. This is done to make it possible to serialize
21
    # AnnifRegistry instances without including the potentially huge objects
22
    # (which contain backends with large models, vocabularies with lots of
23
    # concepts etc). Serialized AnnifRegistry instances can then be passed
24
    # between processes when using the multiprocessing module.
25
    _projects = {}
26
    _vocabs = {}
27
28
    def __init__(self, projects_config_path, datadir, init_projects):
29
        self._rid = id(self)
30
        self._datadir = datadir
31
        self._projects[self._rid] = \
32
            self._create_projects(projects_config_path)
33
        self._vocabs[self._rid] = {}
34
        if init_projects:
35
            for project in self._projects[self._rid].values():
36
                project.initialize()
37
38
    def _create_projects(self, projects_config_path):
39
        # parse the configuration
40
        config = parse_config(projects_config_path)
41
42
        # handle the case where the config file doesn't exist
43
        if config is None:
44
            return {}
45
46
        # create AnnifProject objects from the configuration file
47
        projects = collections.OrderedDict()
48
        for project_id in config.project_ids:
49
            projects[project_id] = AnnifProject(project_id,
50
                                                config[project_id],
51
                                                self._datadir,
52
                                                self)
53
        return projects
54
55
    def get_projects(self, min_access=Access.private):
56
        """Return the available projects as a dict of project_id ->
57
        AnnifProject. The min_access parameter may be used to set the minimum
58
        access level required for the returned projects."""
59
60
        return {project_id: project
61
                for project_id, project in self._projects[self._rid].items()
62
                if project.access >= min_access}
63
64
    def get_project(self, project_id, min_access=Access.private):
65
        """return the definition of a single Project by project_id"""
66
67
        projects = self.get_projects(min_access)
68
        try:
69
            return projects[project_id]
70
        except KeyError:
71
            raise ValueError("No such project {}".format(project_id))
72
73
    def get_vocab(self, vocab_spec, default_language):
74
        """Return an AnnifVocabulary corresponding to the vocab_spec. If no
75
        language information is specified, use the given default language."""
76
        match = re.match(r'(\w+)(\((.*)\))?', vocab_spec)
77
        if match is None:
78
            raise ValueError(
79
                f"Invalid vocabulary specification: {vocab_spec}")
80
        vocab_id = match.group(1)
81
        posargs, kwargs = parse_args(match.group(3))
82
        language = posargs[0] if posargs else default_language
83
        vocab_key = (vocab_id, language)
84
85
        if vocab_key not in self._vocabs[self._rid]:
86
            self._vocabs[self._rid][vocab_key] = AnnifVocabulary(
87
                vocab_id, self._datadir, language)
88
        return self._vocabs[self._rid][vocab_key]
89
90
91
def initialize_projects(app):
92
    projects_config_path = app.config['PROJECTS_CONFIG_PATH']
93
    datadir = app.config['DATADIR']
94
    init_projects = app.config['INITIALIZE_PROJECTS']
95
    app.annif_registry = AnnifRegistry(projects_config_path, datadir,
96
                                       init_projects)
97
98
99
def get_projects(min_access=Access.private):
100
    """Return the available projects as a dict of project_id ->
101
    AnnifProject. The min_access parameter may be used to set the minimum
102
    access level required for the returned projects."""
103
    if not hasattr(current_app, 'annif_registry'):
104
        initialize_projects(current_app)
105
106
    return current_app.annif_registry.get_projects(min_access)
107
108
109
def get_project(project_id, min_access=Access.private):
110
    """return the definition of a single Project by project_id"""
111
112
    projects = get_projects(min_access)
113
    try:
114
        return projects[project_id]
115
    except KeyError:
116
        raise ValueError("No such project {}".format(project_id))
117