More progress on all entites in MW data load

This commit is contained in:
Christopher T. Johnson
2024-05-14 11:08:02 -04:00
parent 7c65b466f1
commit 0acba3ed9b
4 changed files with 96 additions and 30 deletions

View File

@@ -521,8 +521,10 @@ class Definition(QWidget):
self.pronounce.emit(url)
elif url.scheme() == 'word':
self.newWord.emit(url.path())
elif url.scheme() == 'sense':
self.newWord.emit(url.path())
else:
print(f"{clk['fmt'].anchorHref()}: {url.scheme()}")
print(f"{clk['fmt'].anchorHref()}")
self.alert.emit()
self._downClickable = None
return

View File

@@ -1,12 +1,9 @@
import json
from typing import Any, Dict, List, Optional, cast
from typing import Dict, List, Optional, cast
import requests
from PyQt6.QtCore import QPoint, QResource, Qt, QTimer, pyqtSignal, pyqtSlot
from PyQt6.QtGui import (
QBrush,
QColor,
QCursor,
QKeyEvent,
QPainter,
QPainterPath,
@@ -15,7 +12,7 @@ from PyQt6.QtGui import (
QTextCursor,
)
from PyQt6.QtSql import QSqlQuery
from PyQt6.QtWidgets import QDialog, QTextEdit, QWidget
from PyQt6.QtWidgets import QDialog, QWidget
from lib import query_error
from lib.preferences import Preferences
@@ -89,6 +86,7 @@ class ReadDialog(QDialog, Ui_ReadDialog):
self.playSound.connect(self.sound.playSound)
self.playAlert.connect(self.sound.alert)
self.definition.pronounce.connect(self.sound.playSound)
self.definition.newWord.connect(self.newWord)
return
#
@@ -98,6 +96,15 @@ class ReadDialog(QDialog, Ui_ReadDialog):
#
# slots
#
@pyqtSlot(str)
def newWord(self, word: str) -> None:
w = Word(word)
if not w.isValid():
self.playAlert.emit()
return
self.definition.setWord(w)
return
@pyqtSlot()
def timerAction(self) -> None:
if self.session.isActive(): # We are stopping
@@ -127,6 +134,9 @@ class ReadDialog(QDialog, Ui_ReadDialog):
cursor.select(QTextCursor.SelectionType.WordUnderCursor)
text = cursor.selectedText().strip()
word = Word(text)
if not word.isValid():
self.playAlert.emit()
return
word.playPRS()
return
@@ -221,6 +231,9 @@ class ReadDialog(QDialog, Ui_ReadDialog):
cursor.select(cursor.SelectionType.WordUnderCursor)
text = cursor.selectedText().strip()
word = Word(text)
if not word.isValid():
self.playAlert.emit()
return
self.definition.setWord(word)
self.showDefinition()
return

View File

@@ -40,6 +40,7 @@ class Word:
"""All processing of a dictionary word."""
_words: dict[str, WordType] = {}
_valid = False
def __init__(self, word: str) -> None:
#
@@ -62,6 +63,7 @@ class Word:
"definition": json.loads(query.value("definition")),
}
self.current = Word._words[word]
self._valid = True
return
#
# The code should look at our settings to see if we have an API
@@ -70,6 +72,9 @@ class Word:
source = "mw"
self._words[word] = discovered_plugins[source].fetch(word)
if self._words[word] is None:
self._valid = False
return
self.current = Word._words[word]
query.prepare(
"INSERT INTO words "
@@ -81,8 +86,12 @@ class Word:
query.bindValue(":definition", json.dumps(self.current["definition"]))
if not query.exec():
query_error(query)
self._valid = True
return
def isValid(self) -> bool:
return self._valid
@pyqtSlot()
def playSound(self) -> None:
url = discovered_plugins[self.current["source"]].getFirstSound(

View File

@@ -4,7 +4,7 @@ from typing import Any, Literal, NotRequired, TypedDict, cast
from PyQt6.QtCore import QEventLoop, QUrl
from PyQt6.QtGui import QFont, QFontDatabase, QTextCharFormat, QTextLayout
from PyQt6.QtNetwork import QNetworkRequest
from PyQt6.QtNetwork import QNetworkReply, QNetworkRequest
from trycast import trycast
from lib.definition import Fragment, Line
@@ -91,7 +91,7 @@ Inflection = TypedDict(
class CrossReferenceTarget(TypedDict):
cxl: str
cxl: NotRequired[str]
cxr: NotRequired[str]
cxt: str
cxn: NotRequired[str]
@@ -277,7 +277,7 @@ class WordType(TypedDict):
definition: Any
def fetch(word: str) -> WordType:
def fetch(word: str) -> WordType|None:
request = QNetworkRequest()
url = QUrl(API.format(word=word, key=key))
request.setUrl(url)
@@ -287,6 +287,9 @@ def fetch(word: str) -> WordType:
loop = QEventLoop()
reply.finished.connect(loop.quit)
loop.exec()
if reply.error() != QNetworkReply.NetworkError.NoError:
print(f"Error fetching {word}: {reply.errorString()}")
return None
content = reply.readAll()
data = json.loads(content.data().decode("utf-8"))
return {
@@ -295,7 +298,6 @@ def fetch(word: str) -> WordType:
"definition": data,
}
def soundUrl(sound: Sound, fmt="ogg") -> QUrl:
"""Create a URL from a PRS structure."""
base = f"audio://media.merriam-webster.com/audio/prons/en/us/{fmt}"
@@ -343,16 +345,12 @@ def do_prs(frag: Fragment, prs: list[Pronunciation] | None) -> None:
fmt.setAnchorHref(soundUrl(pr["sound"]).toString())
fmt.setForeground(r.linkColor)
#text = pr["mw"] +' \N{SPEAKER} '
text = pr["mw"] +' '
text = ' '+pr["mw"] +' '
else:
text = pr['mw'] + ' '
print(f"text: {text}, length: {len(text)}")
frag.addText(text, fmt)
if "l2" in pr:
frag.addText(pun + pr["l2"], r.subduedLabelFormat)
text = frag.layout().text()
for fmt in frag.layout().formats():
print(f"start: {fmt.start}, length: {fmt.length}, text: \"{text[fmt.start:fmt.start+fmt.length]}\"")
return
@@ -741,6 +739,42 @@ def do_uros(uros: list[UndefinedRunOn]|None) -> list[Line]:
lines.append(line)
lines += newLines
return lines
def do_cxs(cxs: list[CognateCrossRef]|None) -> list[Line]:
assert cxs is not None
r = Resources()
lines: list[Line] = []
for cx in cxs:
frag = Fragment()
frag.addText(cx['cxl']+' ', r.italicFormat)
for cxt in cx['cxtis']:
if 'cxl' in cxt:
frag.addText(cxt['cxl'], r.italicFormat)
text = cxt['cxt']
anchor = text
if 'cxr' in cxt:
anchor = cxt['cxr']
if 'cxn' in cxt:
anchor += f"/{cxt['cxn']}"
fmt = QTextCharFormat(r.smallCapsFormat)
fmt.setAnchor(True)
fmt.setForeground(r.linkColor)
fmt.setFontUnderline(True)
fmt.setUnderlineColor(r.linkColor)
fmt.setFontUnderline(True)
fmt.setAnchorHref('sense:///'+anchor)
#
# XXX - Capitalization does not work
#
text = text.upper()
fmt.setFontPointSize(fmt.fontPointSize() * 0.90)
frag.addText(text, fmt)
line = Line()
line.addFragment(frag)
lines.append(line)
return lines
def getDef(defines: Any) -> list[Line]:
Line.setParseText(parseText)
workList = restructure(defines)
@@ -831,15 +865,17 @@ def getDef(defines: Any) -> list[Line]:
lines.append(line)
line = Line()
frag = Fragment()
if 'def' in work:
defines = trycast(list[DefinitionSection], work["def"])
assert defines is not None
for define in defines:
try:
lines += do_def(define)
except NotImplementedError:
raise
pass
if 'cxs' in work:
lines += do_cxs(trycast(list[CognateCrossRef], work['cxs']))
if "uros" in work:
print(json.dumps(work['uros'],indent=2))
uros = trycast(list[UndefinedRunOn], work['uros'])
lines += do_uros(uros)
if "dros" in work:
@@ -852,10 +888,6 @@ def getDef(defines: Any) -> list[Line]:
phrases.append(line)
phrases += do_dros(dros)
if "et" in work:
line = Line()
frag = Fragment('', r.textFont)
frag.addText(f"{work['fl']} ({used[work['fl']]})",r.labelFormat)
line.addFragment(frag)
ets += do_ets(trycast(list[list[Pair]], work["et"]))
for k in work.keys():
if k not in [
@@ -872,8 +904,9 @@ def getDef(defines: Any) -> list[Line]:
"vrs",
"dros",
'uros',
'cxs',
]:
raise NotImplementedError(f"Unknown key {k} in work")
print( NotImplementedError(f"Unknown key {k} in work"))
if len(phrases) > 0:
lines += phrases
if len(ets) > 0:
@@ -914,6 +947,11 @@ def replaceCode(code:str) -> tuple[str, QTextCharFormat]:
fmt.setFontItalic(True)
elif token == 'sx':
fmt.setFontCapitalization(QFont.Capitalization.SmallCaps)
#
# XXX - Capitalization does not work
#
text = text.upper()
fmt.setFontPointSize(fmt.fontPointSize() * 0.90)
elif token == 'dxt':
if fields[3] == 'illustration':
fmt.setAnchorHref('article:///'+fields[2])
@@ -928,10 +966,14 @@ def replaceCode(code:str) -> tuple[str, QTextCharFormat]:
fmt.setAnchorHref('etymology:///'+fields[2])
else:
fmt.setAnchorHref('etymology:///' + fields[1])
elif token == 'd_link':
if fields[2] != '':
fmt.setAnchorHref('direct:///' + fields[2])
else:
fmt.setAnchorHref('direct:///' + fields[1])
else:
raise NotImplementedError(f"Token {code} not implimented")
fmt.setForeground(r.linkColor)
print(f"Format.capitalization(): {fmt.fontCapitalization()}")
return (text,fmt)
def markup(offset: int, text:str) -> tuple[str, list[QTextLayout.FormatRange]]: