forked from pymorphy2/pymorphy2
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtest_lexemes.py
244 lines (188 loc) · 10.5 KB
/
test_lexemes.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
# -*- coding: utf-8 -*-
from __future__ import absolute_import, unicode_literals
import pytest
# lexemes are divided by blank lines;
# lines that starts with "#" are comments;
# lines that starts with "XFAIL" excludes lexeme from testing.
def parse_lexemes(lexemes_txt):
lexemes_txt = "".join(
line for line in lexemes_txt.strip().splitlines(True)
if not line.startswith("#")
)
return lexemes_txt.split("\n\n")
def get_lexeme_words(lexeme):
lexeme_words = tuple(lexeme.split())
if lexeme_words[0].startswith('XFAIL'):
pytest.xfail()
return lexeme_words
def parse_full_lexeme(lexeme):
forms = lexeme.strip().splitlines()
return [form.split(None, 1) for form in forms]
LEXEMES = parse_lexemes("""
# =========== noun
кот кота коту кота котом коте
коты котов котам котов котами котах
# =========== pronoun
он его него ему нему его него
им ним нём
# =========== pronoun with a particle
он-то его-то него-то ему-то нему-то его-то него-то
им-то ним-то нём-то
# =========== noun with a known prefix
лжекот лжекота лжекоту лжекота лжекотом лжекоте
лжекоты лжекотов лжекотам лжекотов лжекотами лжекотах
# =========== noun with two known prefixes (hyphenated)
экс-лжекот экс-лжекота экс-лжекоту экс-лжекота экс-лжекотом экс-лжекоте
экс-лжекоты экс-лжекотов экс-лжекотам экс-лжекотов экс-лжекотами экс-лжекотах
# =========== noun with two known prefixes
экслжекот экслжекота экслжекоту экслжекота экслжекотом экслжекоте экслжекоты
экслжекотов экслжекотам экслжекотов экслжекотами экслжекотах
# =========== noun witn a guessed prefix
буропёс буропса буропсу буропса буропсом буропсе
буропсы буропсов буропсам буропсов буропсами буропсах
# =========== both parts can be inflected the same way
кот-маг кота-мага коту-магу кота-мага котом-магом коте-маге
коты-маги котов-магов котам-магам котов-магов котами-магами котах-магах
команда-участница команды-участницы команде-участнице команду-участницу командой-участницей командою-участницею команде-участнице
команды-участницы команд-участниц командам-участницам команды-участниц командами-участницами командах-участницах
# =========== prediction using suffix
йотка йотки йотке йотку йоткой йоткою йотке
йотки йоток йоткам йотки йотками йотках
# =========== left part is fixed
кото-пёс кото-пса кото-псу кото-пса кото-псом кото-псе
кото-псы кото-псов кото-псам кото-псов кото-псами кото-псах
# =========== left part is fixed, right is with known prefix
кото-псевдопёс кото-псевдопса кото-псевдопсу кото-псевдопса кото-псевдопсом кото-псевдопсе
кото-псевдопсы кото-псевдопсов кото-псевдопсам кото-псевдопсов кото-псевдопсами кото-псевдопсах
# =========== numeral with gender
два двух двум два двух двумя двух две две два два
# =========== two adverbs
красиво-туманно
# =========== adverb ПО-..
по-театральному
по-западному
# =========== two numerals: one depends on gender, the other doesn't
XFAIL: see https://github.com/kmike/pymorphy2/issues/18
два-три двух-трёх двум-трем два-три двух-трёх двумя-тремя двух-трёх
две-три двух-трёх двум-трем две-три двух-трёх двумя-тремя двух-трёх
два-три двух-трёх двум-трём два-три двумя-тремя двух-трёх
# =========== two nouns that parses differently
человек-гора человека-горы человеку-горе человека-гору человеком-горой человеком-горою человеке-горе
люди-горы людей-гор людям-горам людей-горы людьми-горами людях-горах
гора-человек горы-человека горе-человеку гору-человека горой-человеком горе-человеке
горы-люди гор-людей гор-человек горам-людям горам-человекам горы-людей горами-людьми горами-человеками горах-людях горах-человеках
XFAIL: this is currently too complex
человек-гора человека-горы человеку-горе человека-гору человеком-горой человеком-горою человеке-горе
люди-горы людей-гор человек-гор людям-горам человекам-горам людей-гор людьми-горами человеками-горами людях-горах человеках-горах
# =========== two nouns, one of which has gen1/gen2 forms
лес-колдун леса-колдуна лесу-колдуну лес-колдуна лесом-колдуном лесе-колдуне
леса-колдуны лесов-колдунов лесам-колдунам леса-колдунов лесами-колдунами лесах-колдунах
""")
LEXEMES_FULL = parse_lexemes("""
# ============ noun, a sanity check
кот NOUN,anim,masc sing,nomn
кота NOUN,anim,masc sing,gent
коту NOUN,anim,masc sing,datv
кота NOUN,anim,masc sing,accs
котом NOUN,anim,masc sing,ablt
коте NOUN,anim,masc sing,loct
коты NOUN,anim,masc plur,nomn
котов NOUN,anim,masc plur,gent
котам NOUN,anim,masc plur,datv
котов NOUN,anim,masc plur,accs
котами NOUN,anim,masc plur,ablt
котах NOUN,anim,masc plur,loct
# =========== adverb
театрально ADVB
по-театральному ADVB
# =========== pronoun with a particle
он-то NPRO,masc,3per,Anph sing,nomn
его-то NPRO,masc,3per,Anph sing,gent
него-то NPRO,masc,3per,Anph sing,gent,Af-p
ему-то NPRO,masc,3per,Anph sing,datv
нему-то NPRO,masc,3per,Anph sing,datv,Af-p
его-то NPRO,masc,3per,Anph sing,accs
него-то NPRO,masc,3per,Anph sing,accs,Af-p
им-то NPRO,masc,3per,Anph sing,ablt
ним-то NPRO,masc,3per,Anph sing,ablt,Af-p
нём-то NPRO,masc,3per,Anph sing,loct,Af-p
# ========== initials
И NOUN,anim,masc,Sgtm,Name,Fixd,Abbr,Init sing,nomn
И NOUN,anim,masc,Sgtm,Name,Fixd,Abbr,Init sing,gent
И NOUN,anim,masc,Sgtm,Name,Fixd,Abbr,Init sing,datv
И NOUN,anim,masc,Sgtm,Name,Fixd,Abbr,Init sing,accs
И NOUN,anim,masc,Sgtm,Name,Fixd,Abbr,Init sing,ablt
И NOUN,anim,masc,Sgtm,Name,Fixd,Abbr,Init sing,loct
И NOUN,anim,femn,Sgtm,Name,Fixd,Abbr,Init sing,nomn
И NOUN,anim,femn,Sgtm,Name,Fixd,Abbr,Init sing,gent
И NOUN,anim,femn,Sgtm,Name,Fixd,Abbr,Init sing,datv
И NOUN,anim,femn,Sgtm,Name,Fixd,Abbr,Init sing,accs
И NOUN,anim,femn,Sgtm,Name,Fixd,Abbr,Init sing,ablt
И NOUN,anim,femn,Sgtm,Name,Fixd,Abbr,Init sing,loct
И NOUN,anim,masc,Sgtm,Patr,Fixd,Abbr,Init sing,nomn
И NOUN,anim,masc,Sgtm,Patr,Fixd,Abbr,Init sing,gent
И NOUN,anim,masc,Sgtm,Patr,Fixd,Abbr,Init sing,datv
И NOUN,anim,masc,Sgtm,Patr,Fixd,Abbr,Init sing,accs
И NOUN,anim,masc,Sgtm,Patr,Fixd,Abbr,Init sing,ablt
И NOUN,anim,masc,Sgtm,Patr,Fixd,Abbr,Init sing,loct
И NOUN,anim,femn,Sgtm,Patr,Fixd,Abbr,Init sing,nomn
И NOUN,anim,femn,Sgtm,Patr,Fixd,Abbr,Init sing,gent
И NOUN,anim,femn,Sgtm,Patr,Fixd,Abbr,Init sing,datv
И NOUN,anim,femn,Sgtm,Patr,Fixd,Abbr,Init sing,accs
И NOUN,anim,femn,Sgtm,Patr,Fixd,Abbr,Init sing,ablt
И NOUN,anim,femn,Sgtm,Patr,Fixd,Abbr,Init sing,loct
# ============ UNKN
ьё UNKN
""")
# ============ Tests:
@pytest.mark.parametrize("lexeme", LEXEMES)
def test_has_proper_lexemes(lexeme, morph):
"""
Check if the lexeme of the first word in the lexeme is the same lexeme.
"""
lexeme_words = get_lexeme_words(lexeme)
variants = _lexemes_for_word(lexeme_words[0], morph)
if lexeme_words not in variants:
variants_repr = "\n".join([" ".join(v) for v in variants])
assert False, "%s not in \n%s" % (lexeme, variants_repr)
@pytest.mark.parametrize("lexeme", LEXEMES)
def test_lexemes_sanity(lexeme, morph):
"""
Check if parse.lexeme works properly by applying it several times.
"""
lexeme_words = get_lexeme_words(lexeme)
for word in lexeme_words:
for p in morph.parse(word):
assert p.lexeme[0].lexeme == p.lexeme
@pytest.mark.parametrize("lexeme", LEXEMES)
def test_normalized_is_first(lexeme, morph):
"""
Test that parse.normalized is a first form in lexeme.
"""
lexeme_words = get_lexeme_words(lexeme)
first_parse = morph.parse(lexeme_words[0])[0]
normal_form = (first_parse.word, first_parse.tag.POS)
for word in lexeme_words:
parses = morph.parse(word)
normalized = [(p.normalized.word, p.normalized.tag.POS) for p in parses]
assert normal_form in normalized
@pytest.mark.parametrize("lexeme", LEXEMES_FULL)
def test_full_lexemes(lexeme, morph):
"""
Test that full lexemes are correct.
"""
forms = parse_full_lexeme(lexeme)
forms_lower = [(w.lower(), tag) for w, tag in forms]
for word, tag in forms:
assert_has_full_lexeme(word, forms_lower, morph)
def assert_has_full_lexeme(word, forms, morph):
for p in morph.parse(word):
lexeme_forms = [(f.word, str(f.tag)) for f in p.lexeme]
if lexeme_forms == forms:
return
raise AssertionError("Word %s doesn't have lexeme %s" % (word, forms))
def _lexemes_for_word(word, morph):
res = []
for p in morph.parse(word):
res.append(tuple(f.word for f in p.lexeme))
return res