• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

nielstron / quantulum3 / 897

pending completion
897

push

travis-ci-com

web-flow
Merge pull request #218 from adhardydm/negative-ranges

Enhance parsing of ranges to better handle negative values

22 of 22 new or added lines in 2 files covered. (100.0%)

1513 of 1546 relevant lines covered (97.87%)

4.89 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

92.39
/quantulum3/tests/test_classifier.py
1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3
"""
5✔
4
:mod:`Quantulum` tests.
5
"""
6

7
from __future__ import division
5✔
8

9
import json
5✔
10
import os
5✔
11
import unittest
5✔
12
import urllib.request
5✔
13
from pathlib import Path
5✔
14
from tempfile import TemporaryDirectory
5✔
15
from unittest.mock import patch
5✔
16

17
import joblib
5✔
18
import wikipedia
5✔
19

20
from .. import classifier as clf
5✔
21
from .. import language, load
5✔
22
from .. import parser as p
5✔
23
from .test_setup import (
5✔
24
    add_type_equalities,
25
    load_error_tests,
26
    load_expand_tests,
27
    load_quantity_tests,
28
    multilang,
29
)
30

31
COLOR1 = "\033[94m%s\033[0m"
5✔
32
COLOR2 = "\033[91m%s\033[0m"
5✔
33
TOPDIR = os.path.dirname(__file__) or "."
5✔
34

35

36
###############################################################################
37
class ClassifierBuild(unittest.TestCase):
5✔
38
    """Test suite for the quantulum3 project."""
39

40
    @multilang
5✔
41
    def test_training(self, lang="en_US"):
5✔
42
        """Test that classifier training works"""
43
        # Test that no errors are thrown during training
44
        # Also stores result, to be included in package
45
        self.assertIsNotNone(clf.train_classifier(store=True, lang=lang))
5✔
46

47

48
###############################################################################
49
class ClassifierTest(unittest.TestCase):
5✔
50
    """Test suite for the quantulum3 project."""
51

52
    def setUp(self):
5✔
53
        add_type_equalities(self)
5✔
54
        with (Path(TOPDIR) / "data" / "train.json").open() as f:
5✔
55
            self.custom_training_data = json.load(f)
5✔
56

57
    @multilang
5✔
58
    def test_parse_classifier(self, lang="en_US"):
5✔
59
        """Test that parsing works with classifier usage"""
60
        # forcedly activate classifier
61
        clf.USE_CLF = True
5✔
62

63
        all_tests = load_quantity_tests(False, lang=lang)
5✔
64
        for test in sorted(all_tests, key=lambda x: len(x["req"])):
5✔
65
            with self.subTest(input=test["req"]):
5✔
66
                quants = p.parse(test["req"], lang=lang)
5✔
67

68
                self.assertEqual(
5✔
69
                    len(test["res"]),
70
                    len(quants),
71
                    msg="Differing amount of quantities parsed, expected {}, "
72
                    "got {}: {}, {}".format(
73
                        len(test["res"]), len(quants), test["res"], quants
74
                    ),
75
                )
76
                for index, quant in enumerate(quants):
5✔
77
                    self.assertEqual(quant, test["res"][index])
5✔
78

79
        classifier_tests = load_quantity_tests(True, lang)
5✔
80
        correct = 0
5✔
81
        total = len(classifier_tests)
5✔
82
        error = []
5✔
83
        for test in sorted(classifier_tests, key=lambda x: len(x["req"])):
5✔
84
            quants = p.parse(test["req"], lang=lang)
5✔
85
            if quants == test["res"]:
5✔
86
                correct += 1
5✔
87
            else:
88
                error.append((test, quants))
5✔
89
        success_rate = correct / total
5✔
90
        print("Classifier success rate at {:.2f}%".format(success_rate * 100))
5✔
91
        self.assertGreaterEqual(
5✔
92
            success_rate,
93
            0.8,
94
            "Classifier success rate was at {}%, below 80%.\nFailure at\n{}".format(
95
                success_rate * 100,
96
                "\n".join("{}: {}".format(test[0]["req"], test[1]) for test in error),
97
            ),
98
        )
99

100
    @multilang
5✔
101
    def test_expand(self, lang="en_US"):
5✔
102
        """Test that parsing and expanding works correctly"""
103
        all_tests = load_expand_tests(lang=lang)
5✔
104
        for test in all_tests:
5✔
105
            with self.subTest(input=test["req"]):
5✔
106
                result = p.inline_parse_and_expand(test["req"], lang=lang)
5✔
107
                self.assertEqual(result, test["res"])
5✔
108

109
    @multilang
5✔
110
    def test_errors(self, lang="en_US"):
5✔
111
        """Test that no errors are thrown in edge cases"""
112
        all_tests = load_error_tests(lang=lang)
5✔
113
        for test in all_tests:
5✔
114
            with self.subTest(input=test):
5✔
115
                # pylint: disable=broad-except
116
                p.parse(test, lang=lang)
5✔
117

118
    @unittest.skip("Not necessary, as classifier is live built")
5✔
119
    @multilang
5✔
120
    def test_classifier_up_to_date(self, lang="en_US"):
5✔
121
        """
122
        Test that the classifier has been built with the latest version of
123
        scikit-learn
124
        """
125
        path = language.topdir(lang).joinpath("clf.joblib")
×
126
        with path.open("rb") as clf_file:
×
127
            obj = joblib.load(clf_file)
×
128
        clf_version = obj["scikit-learn_version"]
×
129
        with urllib.request.urlopen(
×
130
            "https://pypi.org/pypi/scikit-learn/json"
131
        ) as response:
132
            cur_version = json.loads(response.read().decode("utf-8"))["info"]["version"]
×
133
        self.assertEqual(
×
134
            clf_version,
135
            cur_version,
136
            "Classifier has been built with scikit-learn version {}, while the"
137
            " newest version is {}. Please update scikit-learn.".format(
138
                clf_version, cur_version
139
            ),
140
        )
141

142
    @multilang
5✔
143
    def test_training(self, lang="en_US"):
5✔
144
        """Test that classifier training works"""
145
        # Test that no errors are thrown during training
146
        obj = clf.train_classifier(store=False, lang=lang)
5✔
147
        # Test that the classifier works with the currently downloaded data
148
        load._CACHE_DICT[id(clf.classifier)] = {
5✔
149
            lang: clf.Classifier(obj=obj, lang=lang)
150
        }
151
        self.test_parse_classifier(lang=lang)
5✔
152

153
    @patch("quantulum3.load.training_set")
5✔
154
    def test_training_custom_data(self, mock_load_training_set):
3✔
155
        """Test the classifier training works with custom data"""
156
        clf.train_classifier(
5✔
157
            store=False,
158
            training_set=self.custom_training_data,
159
        )
160
        mock_load_training_set.assert_not_called()
5✔
161

162
    def test_training_custom_out_path(self):
5✔
163
        """Test the classifier training works with custom out path"""
164

165
        with TemporaryDirectory() as tmpdir:
5✔
166
            out_path = Path(tmpdir) / "clf.joblib"
5✔
167
            clf.train_classifier(
5✔
168
                output_path=out_path,
169
            )
170

171
            self.assertTrue(out_path.exists())
5✔
172

173
    @multilang(["en_us"])
5✔
174
    def test_wikipedia_pages(self, lang):
3✔
175
        wikipedia.set_lang(lang[:2])
5✔
176
        err = []
5✔
177
        for unit in load.units(lang).names.values():
5✔
178
            try:
5✔
179
                wikipedia.page(unit.uri.replace("_", " "), auto_suggest=False)
5✔
180
                pass
5✔
181
            except (
182
                wikipedia.PageError,
183
                wikipedia.DisambiguationError,
184
            ) as e:  # pragma: no cover
185
                err.append((unit, e))
186
        if err:  # pragma: no cover
187
            self.fail("Problematic pages:\n{}".format("\n".join(str(e) for e in err)))
188

189

190
###############################################################################
191
if __name__ == "__main__":  # pragma: no cover
192
    unittest.main()
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc