Parcourir la source

Replace table retrieval with DB call.

scossu il y a 9 mois
Parent
commit
5b3b757b4a

+ 4 - 12
scriptshifter/rest_api.py

@@ -1,7 +1,6 @@
 import logging
 
 from base64 import b64encode
-from copy import deepcopy
 from email.message import EmailMessage
 from json import dumps
 from os import environ, urandom
@@ -15,7 +14,7 @@ from scriptshifter import (
         GIT_COMMIT, GIT_TAG,
         SMTP_HOST, SMTP_PORT)
 from scriptshifter.exceptions import ApiError
-from scriptshifter.tables import list_tables, load_table
+from scriptshifter.tables import list_tables, get_language
 from scriptshifter.trans import transliterate
 
 
@@ -89,16 +88,9 @@ def list_languages():
 @app.route("/table/<lang>")
 def dump_table(lang):
     """
-    Dump parsed transliteration table for a language.
+    Dump a language configuration from the DB.
     """
-    tbl = deepcopy(load_table(lang))
-    for sec_name in ("roman_to_script", "script_to_roman"):
-        if sec_name in tbl:
-            for hname, fn_defs in tbl[sec_name].get("hooks", {}).items():
-                tbl[sec_name]["hooks"][hname] = [
-                        (fn.__name__, kw) for (fn, kw) in fn_defs]
-
-    return jsonify(tbl)
+    return get_language(lang)
 
 
 @app.route("/options/<lang>", methods=["GET"])
@@ -106,7 +98,7 @@ def get_options(lang):
     """
     Get extra options for a table.
     """
-    tbl = load_table(lang)
+    tbl = get_language(lang)
 
     return jsonify(tbl.get("options", []))
 

+ 126 - 9
scriptshifter/tables/__init__.py

@@ -2,9 +2,8 @@ import logging
 import re
 import sqlite3
 
-from functools import cache
 from importlib import import_module
-from json import dumps
+from json import dumps as jdumps, loads as jloads
 from os import R_OK, access, environ, makedirs, path, unlink
 from shutil import move
 
@@ -223,7 +222,7 @@ def populate_table(conn, tid, tname):
                         ) VALUES (?, ?, ?, ?, ?, ?)""",
                         (
                             tid, t_dir, k, i,
-                            hook_data[0].__name__, dumps(hook_data[1:])))
+                            hook_data[0].__name__, jdumps(hook_data[1:])))
 
         # Ignore rules (R2S only).
         for row in sec.get("ignore", []):
@@ -262,14 +261,15 @@ def populate_table(conn, tid, tname):
     for opt in data.get("options", []):
         conn.execute(
                 """INSERT INTO tbl_option (
-                    lang_id, name, label, description, dtype, default_v
-                ) VALUES (?, ?, ?, ?, ?, ?)""",
+                    lang_id, name, label, description, dtype,
+                    options, default_v
+                ) VALUES (?, ?, ?, ?, ?, ?, ?)""",
                 (
                     tid, opt["id"], opt["label"], opt["description"],
-                    opt["type"], opt["default"]))
+                    opt["type"], jdumps(opt.get("options")),
+                    opt["default"]))
 
 
-@cache
 def list_tables():
     """
     List all the indexed tables.
@@ -297,10 +297,9 @@ def list_tables():
     return tdata
 
 
-@cache
 def load_table(tname):
     """
-    Load one transliteration table and possible parents.
+    Parse one transliteration table and possible parents from YML files.
 
     The table file is parsed into an in-memory configuration that contains
     the language & script metadata and parsing rules.
@@ -467,3 +466,121 @@ def load_hook_fn(cname, sec):
             hook_fn[cfg_hook].append((fn, fn_kwargs))
 
     return hook_fn
+
+
+def get_language(lang):
+    """ Get all language options from the DB. """
+
+    conn = sqlite3.connect(DB_PATH)
+
+    with conn:
+        lang_q = conn.execute(
+                """SELECT id, name, label, features, marc_code, description
+                FROM tbl_language WHERE name = ?""", (lang,))
+        lang_data = lang_q.fetchone()
+        lang_id = lang_data[0]
+
+        data = {
+            "name": lang_data[1],
+            "label": lang_data[2],
+            "has_s2r": bool(lang_data[3] & FEAT_S2R),
+            "has_r2s": bool(lang_data[3] & FEAT_R2S),
+            "case_sensitive": not (lang_data[3] & FEAT_CASEI),
+            "marc_code": lang_data[4],
+            "description": lang_data[5],
+        }
+
+        # Normalization.
+
+        norm_q = conn.execute(
+                """SELECT src, dest FROM tbl_normalize
+                WHERE lang_id = ?""",
+                (lang_id,))
+        norm_data = {row[0]: row[1] for row in norm_q}
+        if len(norm_data):
+            data["normalize"] = norm_data
+
+        # Script to Roman map and hooks.
+
+        if data["has_s2r"]:
+            data["script_to_roman"] = {}
+            s2r_q = conn.execute(
+                    """SELECT src, dest FROM tbl_trans_map
+                    WHERE lang_id = ? AND dir = ?""",
+                    (lang_id, FEAT_S2R))
+            s2r_map = tuple((row[0], row[1]) for row in s2r_q)
+            if len(s2r_map):
+                data["script_to_roman"]["map"] = s2r_map
+
+            hooks_q = conn.execute(
+                    """SELECT name, fn, signature
+                    FROM tbl_hook WHERE lang_id = ? AND dir = ?
+                    ORDER BY sort""",
+                    (lang_id, FEAT_S2R))
+            s2r_hooks = [
+                {
+                    "name": row[0],
+                    "fn": row[1],
+                    "signature": jloads(row[2]),
+                } for row in hooks_q
+            ]
+            if len(s2r_hooks):
+                data["script_to_roman"]["hooks"] = s2r_hooks
+
+        # Roman to script map, ignore list, and hooks.
+
+        if data["has_r2s"]:
+            data["roman_to_script"] = {}
+            r2s_q = conn.execute(
+                    """SELECT src, dest FROM tbl_trans_map
+                    WHERE lang_id = ? AND dir = ?""",
+                    (lang_id, FEAT_R2S))
+            r2s_map = tuple((row[0], row[1]) for row in r2s_q)
+            if len(r2s_map):
+                data["roman_to_script"]["map"] = r2s_map
+
+            ignore_q = conn.execute(
+                    """SELECT rule, features FROM tbl_ignore
+                    WHERE lang_id = ?""",
+                    (lang_id,))
+            # Features (regular expressions) not implemented yet.
+            r2s_ignore = tuple(row[0] for row in ignore_q)
+            if len(r2s_ignore):
+                data["roman_to_script"]["ignore"] = r2s_ignore
+
+            hooks_q = conn.execute(
+                    """SELECT name, fn, signature
+                    FROM tbl_hook WHERE lang_id = ? AND dir = ?
+                    ORDER BY sort""",
+                    (lang_id, FEAT_R2S))
+            r2s_hooks = [
+                {
+                    "name": row[0],
+                    "fn": row[1],
+                    "signature": jloads(row[2]),
+                } for row in hooks_q
+            ]
+            if len(r2s_hooks):
+                data["roman_to_script"]["hooks"] = r2s_hooks
+
+        options_q = conn.execute(
+                """SELECT name, label, description, dtype, options, default_v
+                FROM tbl_option
+                WHERE lang_id = ?""",
+                (lang_id,))
+
+        opt_data = tuple(
+            {
+                "id": row[0],
+                "label": row[1],
+                "description": row[2],
+                "type": row[3],
+                "options": jloads(row[4]) if row[4] else None,
+                "default": row[5],
+            }
+            for row in options_q
+        )
+        if len(opt_data):
+            data["options"] = opt_data
+
+        return data

+ 1 - 1
scriptshifter/tables/data/yiddish.yml

@@ -4,7 +4,7 @@ general:
 options:
   - id: loshn_koydesh
     label: Loshn Koydesh
-    description: "[TODO]"
+    description: "Apply Loshn Koydesh vocalization."
     type: boolean
     default: false
 

+ 1 - 0
scriptshifter/tables/init.sql

@@ -91,6 +91,7 @@ CREATE TABLE tbl_option (
     label TEXT NOT NULL,
     description TEXT,
     dtype TEXT,
+    options TEXT,
     default_v TEXT,
 
     FOREIGN KEY (lang_id) REFERENCES tbl_language(id) ON DELETE CASCADE