Repository: tatuylonen/wiktextract

Issue:
Comparative adjectives in Russian dictionary
It has been detected that, in some Russian dictionary entries, the comparative degree is not being extracted correctly from Wiktionary. Two representative examples are detailed below, as the rest of the checked adjectives present the information correctly:

- In the word “опасный”, the form of the comparative degree corresponds to a number, while in Wiktionary the following appears "Прилагательное, качественнное, тип склонения по классификациии А. Зализняка - 1*a. Сравнительная степепень - опа́снеее, опа́сней.", so I understand that it is not correctly extracted.

![Image](https://github.com/user-attachments/assets/db2cd237-1ca0-4943-a611-82f5d46eb718)

- In the word “смелый” the comparative form does not even exist, while in Wiktionary the following appears "Прилагагательное, качественнное, тип склонения по класссификациии А. Зализняка - 1a/c'. Сравнительная степепень - смеле́е, смелеле́й, посмелеле́е, посмеле́й.", so I understand that it was not extracted correctly.

Hints from issue comments:

Solution patch:
diff --git a/src/wiktextract/extractor/ru/inflection.py b/src/wiktextract/extractor/ru/inflection.py
index dc2b6c2c..5b7bc333 100644
--- a/src/wiktextract/extractor/ru/inflection.py
+++ b/src/wiktextract/extractor/ru/inflection.py
@@ -190,3 +190,25 @@ def add_form_data(
     if len(form.form) > 0 and form.form != "—":
         translate_raw_tags(form)
         word_entry.forms.append(form)
+
+
+def extract_прил_ru_comparative_forms(
+    wxr: WiktextractContext, word_entry: WordEntry, expanded_node: WikiNode
+) -> None:
+    after_comparative = False
+    for node in expanded_node.children:
+        if isinstance(node, str):
+            node_str = clean_node(wxr, None, node)
+            if node_str.endswith("Сравнительная степень —"):
+                after_comparative = True
+        elif (
+            after_comparative
+            and isinstance(node, WikiNode)
+            and node.kind == NodeKind.ITALIC
+        ):
+            for link_node in node.find_child(NodeKind.LINK):
+                form = clean_node(wxr, None, link_node)
+                if form != "":
+                    word_entry.forms.append(
+                        Form(form=form, tags=["comparative"])
+                    )
diff --git a/src/wiktextract/extractor/ru/page.py b/src/wiktextract/extractor/ru/page.py
index 9b3580e8..21d24371 100644
--- a/src/wiktextract/extractor/ru/page.py
+++ b/src/wiktextract/extractor/ru/page.py
@@ -15,7 +15,11 @@ from ...wxr_context import WiktextractContext
 from ...wxr_logging import logger
 from .etymology import extract_etymology
 from .gloss import extract_gloss, process_meaning_template
-from .inflection import parse_html_forms_table, parse_wikitext_forms_table
+from .inflection import (
+    extract_прил_ru_comparative_forms,
+    parse_html_forms_table,
+    parse_wikitext_forms_table,
+)
 from .linkage import (
     extract_alt_form_section,
     extract_linkage_section,
@@ -141,11 +145,6 @@ def get_pos(
 def extract_morphological_section(
     wxr: WiktextractContext, page_data: list[WordEntry], level_node: WikiNode
 ) -> None:
-    param_tag_map = {
-        "степень": "comparative",  # Шаблон:inflection/ru/adj
-        "соотв": "perfective",  # Шаблон:Гл-блок
-    }
-
     pos_data = get_pos(wxr, level_node)
     if pos_data is not None:
         page_data[-1].pos = pos_data["pos"]
@@ -180,6 +179,11 @@ def extract_morphological_section(
                 wxr, None, child_node.template_parameters.get("слоги", "")
             )
 
+        if child_node.template_name.startswith("прил ru"):
+            extract_прил_ru_comparative_forms(
+                wxr, page_data[-1], expanded_template
+            )
+
         for node in expanded_template.children:
             node_text = clean_node(wxr, page_data[-1], node)
             for text in node_text.split(","):
@@ -191,16 +195,6 @@ def extract_morphological_section(
                     elif isinstance(tr_tag, list):
                         page_data[-1].tags.extend(tr_tag)
 
-        for param, tag in param_tag_map.items():
-            if param in child_node.template_parameters:
-                forms_text = clean_node(
-                    wxr, None, child_node.template_parameters[param]
-                )
-                for form in forms_text.split(","):
-                    form = form.strip()
-                    if form != "":
-                        page_data[-1].forms.append(Form(form=form, tags=[tag]))
-
 
 def parse_section(
     wxr: WiktextractContext, page_data: list[WordEntry], level_node: WikiNode


Test patch:
diff --git a/tests/test_ru_gloss.py b/tests/test_ru_gloss.py
index 79ef29c5..46d053a5 100644
--- a/tests/test_ru_gloss.py
+++ b/tests/test_ru_gloss.py
@@ -203,7 +203,6 @@ class TestRUGloss(unittest.TestCase):
                         "Глаголы в видовых парах",
                         "Глаголы, спряжение 1a",
                     ],
-                    "forms": [{"form": "прыгнуть", "tags": ["perfective"]}],
                     "lang": "Русский",
                     "lang_code": "ru",
                     "word": "прыгать",
diff --git a/tests/test_ru_inflection.py b/tests/test_ru_inflection.py
index cfd57ba5..7cd46073 100644
--- a/tests/test_ru_inflection.py
+++ b/tests/test_ru_inflection.py
@@ -4,7 +4,10 @@ from wikitextprocessor import Wtp
 
 from wiktextract.config import WiktionaryConfig
 from wiktextract.extractor.ru.models import WordEntry
-from wiktextract.extractor.ru.page import extract_morphological_section
+from wiktextract.extractor.ru.page import (
+    extract_morphological_section,
+    parse_page,
+)
 from wiktextract.wxr_context import WiktextractContext
 
 
@@ -13,7 +16,10 @@ class TestLinkage(TestCase):
 
     def setUp(self) -> None:
         self.wxr = WiktextractContext(
-            Wtp(lang_code="ru"), WiktionaryConfig(dump_file_lang_code="ru")
+            Wtp(lang_code="ru"),
+            WiktionaryConfig(
+                dump_file_lang_code="ru", capture_language_codes=None
+            ),
         )
 
     def tearDown(self) -> None:
@@ -243,3 +249,35 @@ class TestLinkage(TestCase):
                 {"form": "водо", "tags": ["vocative", "singular"]},
             ],
         )
+
+    def test_comparative_forms(self):
+        self.wxr.wtp.add_page("Шаблон:-ru-", 10, "Русский")
+        self.wxr.wtp.add_page(
+            "Шаблон:прил ru 1*a",
+            10,
+            "[[прилагательное|Прилагательное]], [[качественное прилагательное|качественное]], тип склонения по [[Викисловарь:Использование словаря Зализняка|классификации А.&#160;Зализняка]]&#160;— 1*a. Сравнительная степень&nbsp;— ''[[опаснее#опа́снее|опа́снее]], [[опасней#опа́сней|опа́сней]].''",
+        )
+        data = parse_page(
+            self.wxr,
+            "опасный",
+            """= {{-ru-}} =
+=== Морфологические и синтаксические свойства ===
+{{прил ru 1*a
+|основа=опа́сн
+|основа1=опа́сен
+|тип=качественное
+|слоги={{по слогам|о|.|па́с|ный}}
+|степень=1
+|краткая=
+}}
+=== Семантические свойства ===
+==== Значение ====
+# [[способный]] причинить [[вред]], угрожающий [[несчастье]]м {{пример|}}""",
+        )
+        self.assertEqual(
+            data[0]["forms"],
+            [
+                {"form": "опа́снее", "tags": ["comparative"]},
+                {"form": "опа́сней", "tags": ["comparative"]},
+            ],
+        )