Skip to content

Commit d907024

Browse files
authored
Merge pull request #820 from NatLibFi/fix-optional-analyzer-use-importlib
Smarter initialization of optional analyzers
2 parents 4809561 + 419f8df commit d907024

File tree

6 files changed

+35
-21
lines changed

6 files changed

+35
-21
lines changed

annif/analyzer/__init__.py

+7-17
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import annif
99
from annif.util import parse_args
1010

11-
from . import simple, simplemma, snowball
11+
from . import simple, simplemma, snowball, spacy, voikko
1212

1313
if TYPE_CHECKING:
1414
from annif.analyzer.analyzer import Analyzer
@@ -17,7 +17,10 @@
1717

1818

1919
def register_analyzer(analyzer):
20-
_analyzers[analyzer.name] = analyzer
20+
if analyzer.is_available():
21+
_analyzers[analyzer.name] = analyzer
22+
else:
23+
annif.logger.debug(f"{analyzer.name} analyzer not available, not enabling it")
2124

2225

2326
def get_analyzer(analyzerspec: str) -> Analyzer:
@@ -37,18 +40,5 @@ def get_analyzer(analyzerspec: str) -> Analyzer:
3740
register_analyzer(simple.SimpleAnalyzer)
3841
register_analyzer(snowball.SnowballAnalyzer)
3942
register_analyzer(simplemma.SimplemmaAnalyzer)
40-
41-
# Optional analyzers
42-
try:
43-
from . import voikko
44-
45-
register_analyzer(voikko.VoikkoAnalyzer)
46-
except ImportError:
47-
annif.logger.debug("voikko not available, not enabling voikko analyzer")
48-
49-
try:
50-
from . import spacy
51-
52-
register_analyzer(spacy.SpacyAnalyzer)
53-
except ImportError:
54-
annif.logger.debug("spaCy not available, not enabling spacy analyzer")
43+
register_analyzer(voikko.VoikkoAnalyzer)
44+
register_analyzer(spacy.SpacyAnalyzer)

annif/analyzer/analyzer.py

+5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ class Analyzer(metaclass=abc.ABCMeta):
2222
name = None
2323
token_min_length = 3 # default value, can be overridden in instances
2424

25+
@staticmethod
26+
def is_available() -> bool:
27+
"""Return True if the analyzer is available for use, False if not."""
28+
return True # can be overridden in implementations if necessary
29+
2530
def __init__(self, **kwargs) -> None:
2631
if _KEY_TOKEN_MIN_LENGTH in kwargs:
2732
self.token_min_length = int(kwargs[_KEY_TOKEN_MIN_LENGTH])

annif/analyzer/spacy.py

+7
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
from __future__ import annotations
44

5+
import importlib
6+
57
import annif.util
68
from annif.exception import OperationFailedException
79

@@ -13,6 +15,11 @@
1315
class SpacyAnalyzer(analyzer.Analyzer):
1416
name = "spacy"
1517

18+
@staticmethod
19+
def is_available() -> bool:
20+
# return True iff spaCy is installed
21+
return importlib.util.find_spec("spacy") is not None
22+
1623
def __init__(self, param: str, **kwargs) -> None:
1724
import spacy
1825

annif/analyzer/voikko.py

+8-2
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,19 @@
33
from __future__ import annotations
44

55
import functools
6-
7-
import voikko.libvoikko
6+
import importlib
87

98
from . import analyzer
109

1110

1211
class VoikkoAnalyzer(analyzer.Analyzer):
1312
name = "voikko"
1413

14+
@staticmethod
15+
def is_available() -> bool:
16+
# return True iff Voikko is installed
17+
return importlib.util.find_spec("voikko") is not None
18+
1519
def __init__(self, param: str, **kwargs) -> None:
1620
self.param = param
1721
self.voikko = None
@@ -26,6 +30,8 @@ def __getstate__(self) -> dict[str, str | None]:
2630

2731
@functools.lru_cache(maxsize=500000)
2832
def _normalize_word(self, word: str) -> str:
33+
import voikko.libvoikko
34+
2935
if self.voikko is None:
3036
self.voikko = voikko.libvoikko.Voikko(self.param)
3137
result = self.voikko.analyze(word)

tests/test_analyzer_spacy.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,12 @@
33
import pytest
44

55
import annif.analyzer
6+
import annif.analyzer.spacy
67
from annif.exception import OperationFailedException
78

8-
spacy = pytest.importorskip("spacy")
9+
pytestmark = pytest.mark.skipif(
10+
not annif.analyzer.spacy.SpacyAnalyzer.is_available(), reason="spaCy is required"
11+
)
912

1013

1114
def test_spacy_model_not_found():

tests/test_analyzer_voikko.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33
import pytest
44

55
import annif.analyzer
6+
import annif.analyzer.voikko
67

7-
voikko = pytest.importorskip("annif.analyzer.voikko")
8+
pytestmark = pytest.mark.skipif(
9+
not annif.analyzer.voikko.VoikkoAnalyzer.is_available(), reason="voikko is required"
10+
)
811

912

1013
def test_voikko_getstate():

0 commit comments

Comments
 (0)