Skip to content

Commit

Permalink
feat: port para json api
Browse files Browse the repository at this point in the history
  • Loading branch information
kod-kristoff committed Apr 17, 2024
1 parent 2706981 commit c3bcee5
Show file tree
Hide file tree
Showing 11 changed files with 509 additions and 8 deletions.
3 changes: 3 additions & 0 deletions src/sblex/application/queries/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from sblex.application.queries.inflection import InflectionTableQuery, InflectionTableRow
from sblex.application.queries.lex_fullforms import FullformLex, FullformLexQuery
from sblex.application.queries.lookup_lid import LookupLid
from sblex.application.queries.paradigms import NoPartOfSpeechOnBaseform, Paradigms

__all__ = [
"FullformLex",
Expand All @@ -10,4 +11,6 @@
"FullformQuery",
"InflectionTableQuery",
"InflectionTableRow",
"Paradigms",
"NoPartOfSpeechOnBaseform",
]
26 changes: 26 additions & 0 deletions src/sblex/application/queries/paradigms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import abc
import typing


class Paradigms(abc.ABC):
@abc.abstractmethod
def query(self, s: str) -> typing.Tuple[str, list[str]]: ...

def prepare_args(self, s: str) -> typing.Tuple[str, list[str]]:
xs = [x.strip() for x in s.split(",") if len(x) > 0]
baseform, pos = split_word_and_pos(xs[0])
xs[0] = f"{baseform}:{pos}"
return baseform, xs


def split_word_and_pos(s: str) -> typing.Tuple[str, str]:
n = s.find(":")
if n == -1:
raise NoPartOfSpeechOnBaseform()

Check warning on line 19 in src/sblex/application/queries/paradigms.py

View check run for this annotation

Codecov / codecov/patch

src/sblex/application/queries/paradigms.py#L19

Added line #L19 was not covered by tests
word = s[:n].strip()
pos = s[n + 1 :].strip()
return word, pos


class NoPartOfSpeechOnBaseform(Exception):
"""The baseform must contain a Part-of-Speech tag."""
33 changes: 29 additions & 4 deletions src/sblex/fm/fm_runner.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import logging
import subprocess
import sys
from pathlib import Path
from typing import TypedDict
import typing

from json_arrays import jsonlib
from opentelemetry import trace
Expand All @@ -26,18 +28,26 @@ def __init__(self, binary_path: Path, *, locale: str | None = None) -> None:
self.locale = locale or 'LC_ALL="sv_SE.UTF-8"'

def inflection(self, paradigm: str, word: str) -> list[InflectionRow]:
with tracer.start_as_current_span("call_fm_binary") as call_span:
args = f'{paradigm} "{word}";'
program = [
with trace.get_tracer(__name__).start_as_current_span(

Check warning on line 31 in src/sblex/fm/fm_runner.py

View check run for this annotation

Codecov / codecov/patch

src/sblex/fm/fm_runner.py#L31

Added line #L31 was not covered by tests
sys._getframe().f_code.co_name
) as _call_span:
program: list[typing.Union[str, Path]] = [

Check warning on line 34 in src/sblex/fm/fm_runner.py

View check run for this annotation

Codecov / codecov/patch

src/sblex/fm/fm_runner.py#L34

Added line #L34 was not covered by tests
self.binary_path,
"-i",
]
args = f'{paradigm} "{word}";'
return self._call_fm_binary(program=program, args=args)

Check warning on line 39 in src/sblex/fm/fm_runner.py

View check run for this annotation

Codecov / codecov/patch

src/sblex/fm/fm_runner.py#L39

Added line #L39 was not covered by tests

def _call_fm_binary(self, program: list[typing.Union[str, Path]], args: str):
with trace.get_tracer(__name__).start_as_current_span(

Check warning on line 42 in src/sblex/fm/fm_runner.py

View check run for this annotation

Codecov / codecov/patch

src/sblex/fm/fm_runner.py#L42

Added line #L42 was not covered by tests
sys._getframe().f_code.co_name
) as call_span:
call_span.set_attribute("program", str(program))
call_span.set_attribute("args", args)
process = subprocess.run(
program, # type: ignore # noqa: S603
input=args.encode("utf-8"),
check=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
Expand All @@ -47,10 +57,25 @@ def inflection(self, paradigm: str, word: str) -> list[InflectionRow]:
extra={
"stderr": process.stderr.decode("utf-8"),
"binary_path": self.binary_path,
"program": str(program),
"args": args,
},
)

raise RuntimeError("Call to `fm-sblex` failed")
raw_data = process.stdout.strip()
raw_data = process.stdout

Check warning on line 66 in src/sblex/fm/fm_runner.py

View check run for this annotation

Codecov / codecov/patch

src/sblex/fm/fm_runner.py#L66

Added line #L66 was not covered by tests
return jsonlib.loads(raw_data) if len(raw_data) > 0 else []

def paradigms(self, words: list[str]) -> list[str]:
with trace.get_tracer(__name__).start_as_current_span(

Check warning on line 70 in src/sblex/fm/fm_runner.py

View check run for this annotation

Codecov / codecov/patch

src/sblex/fm/fm_runner.py#L70

Added line #L70 was not covered by tests
sys._getframe().f_code.co_name
) as _call_span:
program: list[typing.Union[str, Path]] = [

Check warning on line 73 in src/sblex/fm/fm_runner.py

View check run for this annotation

Codecov / codecov/patch

src/sblex/fm/fm_runner.py#L73

Added line #L73 was not covered by tests
self.binary_path,
"-f",
]
args = ",".join(words)
return self._call_fm_binary(

Check warning on line 78 in src/sblex/fm/fm_runner.py

View check run for this annotation

Codecov / codecov/patch

src/sblex/fm/fm_runner.py#L77-L78

Added lines #L77 - L78 were not covered by tests
program=program,
args=args,
)
22 changes: 22 additions & 0 deletions src/sblex/infrastructure/queries/fm_runner_paradigms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import sys
import typing

from opentelemetry import trace
from sblex.application.queries import Paradigms
from sblex.fm import FmRunner


class FmRunnerParadigms(Paradigms):
def __init__(self, *, fm_runner: FmRunner) -> None:
super().__init__()
self.fm_runner = fm_runner

def query(self, s: str) -> typing.Tuple[str, list]:
with trace.get_tracer(__name__).start_as_current_span(
sys._getframe().f_code.co_name
) as _process_api_span:
baseform, words = self.prepare_args(s)
print(f"{baseform=}, {words=}")
print(f"{type(self.fm_runner)=}")
result = self.fm_runner.paradigms(words)
return baseform, result
6 changes: 6 additions & 0 deletions src/sblex/saldo_ws/deps.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
from fastapi import Depends, Request
from sblex.application.queries import FullformLexQuery, LookupLid
from sblex.application.queries.inflection import InflectionTableQuery
from sblex.application.queries.paradigms import Paradigms
from sblex.application.services import LookupService
from sblex.fm import Morphology
from sblex.fm.fm_runner import FmRunner
from sblex.infrastructure.queries import LookupFullformLexQuery
from sblex.infrastructure.queries.fm_runner_inflection import FmRunnerInflectionTable
from sblex.infrastructure.queries.fm_runner_paradigms import FmRunnerParadigms
from sblex.infrastructure.queries.http_morpology import HttpMorphology


Expand Down Expand Up @@ -48,3 +50,7 @@ def get_fullform_lex_query(
lookup_service: LookupService = Depends(get_lookup_service), # noqa: B008
) -> FullformLexQuery:
return LookupFullformLexQuery(lookup_service=lookup_service)


def get_paradigms(fm_runner: FmRunner = Depends(get_fm_runner)) -> Paradigms: # noqa: B008
return FmRunnerParadigms(fm_runner=fm_runner)
2 changes: 2 additions & 0 deletions src/sblex/saldo_ws/routes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
fullform_lex,
inflection,
lids,
paradigms,
system_info,
)

Expand All @@ -18,4 +19,5 @@
compounds.router, prefix="/sms", tags=["sms", "sammansättning", "compound"]
)
router.include_router(inflection.router, prefix="/gen", tags=["inflection"])
router.include_router(paradigms.router, prefix="/para", tags=["paradigms"])
router.include_router(system_info.router, tags=["system-info"])
18 changes: 18 additions & 0 deletions src/sblex/saldo_ws/routes/paradigms.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import sys

from fastapi import APIRouter, Depends
from opentelemetry import trace
from sblex.application.queries import Paradigms
from sblex.saldo_ws import deps

router = APIRouter()


@router.get("/json/{words}", response_model=list[str])
async def get_para_json(words: str, paradigms: Paradigms = Depends(deps.get_paradigms)): # noqa: B008
with trace.get_tracer(__name__).start_as_current_span(
sys._getframe().f_code.co_name
) as _process_api_span:
print(f"{words=}")
_baseform, result = paradigms.query(words)
return result
14 changes: 11 additions & 3 deletions tests/adapters/mem_fm_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,16 @@


class MemFmRunner(FmRunner):
def __init__(self, paradigms: dict[str, dict[str, list[InflectionRow]]]) -> None:
self.paradigms = paradigms
def __init__(
self,
paradigms: dict[str, dict[str, list[InflectionRow]]],
word_to_paradigm: dict[str, list[str]],
) -> None:
self._paradigms = paradigms
self._word_to_paradigm = word_to_paradigm

def inflection(self, paradigm: str, word: str) -> list[InflectionRow]:
return self.paradigms.get(paradigm, {}).get(word) or []
return self._paradigms.get(paradigm, {}).get(word) or []

def paradigms(self, words: list[str]):
return self._word_to_paradigm.get(words[0], [])
Loading

0 comments on commit c3bcee5

Please sign in to comment.