checkpoint
This commit is contained in:
@@ -1,12 +1,12 @@
|
||||
from PyQt6.QtGui import QColor
|
||||
from trycast import trycast
|
||||
import json
|
||||
import re
|
||||
from typing import Any, Literal, NamedTuple, NotRequired, TypedDict, cast
|
||||
from typing import Any, NamedTuple, NotRequired, TypedDict
|
||||
|
||||
from PyQt6.QtCore import QEventLoop, QUrl, Qt
|
||||
from PyQt6.QtGui import QColor, QFont
|
||||
from PyQt6.QtNetwork import QNetworkRequest
|
||||
from lib.words import Word
|
||||
from lib.utils import Resources
|
||||
from lib.definition import Line, Fragment
|
||||
|
||||
registration = {
|
||||
@@ -27,10 +27,6 @@ class VerbalIllustration(TypedDict):
|
||||
t: str
|
||||
aq: str
|
||||
|
||||
class VerbalIllustrationTuple(NamedTuple):
|
||||
type_: str # 'vis'
|
||||
data: list[VerbalIllustration]
|
||||
|
||||
class Sound(TypedDict):
|
||||
audio: str
|
||||
ref: str
|
||||
@@ -38,12 +34,10 @@ class Sound(TypedDict):
|
||||
|
||||
class Pronunciation(TypedDict):
|
||||
mw: str
|
||||
l: str
|
||||
l2: str
|
||||
pun: str
|
||||
sound: Sound
|
||||
|
||||
|
||||
l: NotRequired[str]
|
||||
l2: NotRequired[str]
|
||||
pun: NotRequired[str]
|
||||
sound: NotRequired[Sound]
|
||||
|
||||
class Meta(TypedDict):
|
||||
id: str
|
||||
@@ -56,12 +50,12 @@ class Meta(TypedDict):
|
||||
|
||||
class HeadWordInfo(TypedDict):
|
||||
hw: str
|
||||
prs: list[Pronunciation]
|
||||
prs: NotRequired[list[Pronunciation]]
|
||||
|
||||
class HeadWord(TypedDict):
|
||||
hw: str
|
||||
prs: list[Pronunciation]
|
||||
psl: str
|
||||
prs: NotRequired[list[Pronunciation]]
|
||||
psl: NotRequired[str]
|
||||
|
||||
class Variant(TypedDict):
|
||||
va: str
|
||||
@@ -109,34 +103,26 @@ class RunInWrap(TypedDict):
|
||||
text: str
|
||||
vrs: list[Variant]
|
||||
|
||||
class Sense:
|
||||
dt: list[str] # not full
|
||||
et: list[str] # not full
|
||||
ins: list[Inflection]
|
||||
lbs: list[str]
|
||||
prs: list[Pronunciation]
|
||||
sdsense: DividedSense
|
||||
sgram: str
|
||||
sls: list[str]
|
||||
sn: str
|
||||
vrs: list[Variant]
|
||||
|
||||
class SenseSequence(TypedDict):
|
||||
sense: Sense
|
||||
sen: Sense
|
||||
class Sense(TypedDict):
|
||||
dt: list[list] # not full
|
||||
et: NotRequired[list[str]]
|
||||
ins: NotRequired[list[Inflection]]
|
||||
lbs: NotRequired[list[str]]
|
||||
prs: NotRequired[list[Pronunciation]]
|
||||
sdsense: NotRequired[DividedSense]
|
||||
sgram: NotRequired[str]
|
||||
sls: NotRequired[list[str]]
|
||||
sn: NotRequired[str]
|
||||
vrs: NotRequired[list[Variant]]
|
||||
|
||||
class Definition(TypedDict):
|
||||
sseq: list[SenseSequence]
|
||||
vd: str
|
||||
sseq: list[list[list[Any]]]
|
||||
vd: NotRequired[str]
|
||||
|
||||
class Pair(TypedDict):
|
||||
objType: str
|
||||
obj: list[Sense]|Sense|str|list[VerbalIllustration]|list[Any]
|
||||
|
||||
class EntryX(TypedDict):
|
||||
meta: Meta
|
||||
hom: NotRequired[str]
|
||||
hwi: HeadWordInfo
|
||||
ahws: NotRequired[list[HeadWord]]
|
||||
vrs: NotRequired[list[Variant]]
|
||||
fl: str
|
||||
def_: list[Definition]
|
||||
Entry = TypedDict(
|
||||
'Entry',
|
||||
{
|
||||
@@ -149,13 +135,29 @@ Entry = TypedDict(
|
||||
'def': list[Definition],
|
||||
}
|
||||
)
|
||||
class WordType(TypedDict):
|
||||
word: str
|
||||
source: str
|
||||
definition: dict[str, Any]
|
||||
|
||||
def fetch(word:str) -> dict[str, Any]:
|
||||
def make_pairs(src: list[Any]) -> list[Pair]:
|
||||
result:list[Pair] = []
|
||||
iters = [iter(src)]*2
|
||||
for entry in zip(*iters):
|
||||
pair = { 'objType': entry[0],
|
||||
'obj': entry[1],
|
||||
}
|
||||
pair = trycast(Pair, pair)
|
||||
assert pair is not None
|
||||
result.append(pair)
|
||||
return result
|
||||
|
||||
def fetch(word:str) -> WordType:
|
||||
request = QNetworkRequest()
|
||||
url = QUrl(API.format(word=word, key=key))
|
||||
request.setUrl(url)
|
||||
request.setTransferTimeout(3000)
|
||||
reply = Word._nam.get(request)
|
||||
reply = Resources.nam.get(request)
|
||||
assert reply is not None
|
||||
loop = QEventLoop()
|
||||
reply.finished.connect(loop.quit)
|
||||
@@ -195,16 +197,16 @@ def getFirstSound(definition: list[Entry]) -> QUrl:
|
||||
return url
|
||||
return QUrl()
|
||||
|
||||
def do_prs(prs: list[Pronunciation]) -> list[Fragment]:
|
||||
def do_prs(hwi: HeadWordInfo) -> list[Fragment]:
|
||||
r = Resources()
|
||||
frags: list[Fragment] = []
|
||||
font = trycast(QFont, Word._resources['fonts']['label'])
|
||||
assert font is not None
|
||||
linkColor = trycast(QColor, Word._resources['colors']['link'])
|
||||
assert linkColor is not None
|
||||
subduedColor = trycast(QColor, Word._resources['colors']['subdued'])
|
||||
assert subduedColor is not None
|
||||
font = r.labelFont
|
||||
linkColor = r.linkColor
|
||||
subduedColor = r.subduedColor
|
||||
|
||||
for pr in prs:
|
||||
if 'prs' not in hwi:
|
||||
return []
|
||||
for pr in hwi['prs']:
|
||||
if 'pun' in pr:
|
||||
pun = pr['pun']
|
||||
else:
|
||||
@@ -216,6 +218,7 @@ def do_prs(prs: list[Pronunciation]) -> list[Fragment]:
|
||||
frag = Fragment(pr['mw'], font, color=subduedColor)
|
||||
if 'sound' in pr:
|
||||
frag.setAudio(soundUrl(pr['sound']))
|
||||
frag.setColor(linkColor)
|
||||
frags.append(frag)
|
||||
if 'l2' in pr:
|
||||
frags.append(
|
||||
@@ -223,38 +226,141 @@ def do_prs(prs: list[Pronunciation]) -> list[Fragment]:
|
||||
)
|
||||
return frags
|
||||
|
||||
def do_sense(sense: Sense|None) -> tuple[list[Fragment], list[Line]]:
|
||||
if sense is None:
|
||||
return ([],[])
|
||||
lines: list[Line] = []
|
||||
frags: list[Fragment] = []
|
||||
r = Resources()
|
||||
if 'sn' in sense:
|
||||
sn = sense['sn']
|
||||
else:
|
||||
sn = ''
|
||||
print(f'{sn}\n\n',json.dumps(sense['dt'], indent=2))
|
||||
iters = [iter(sense['dt'])]*2
|
||||
for pair in zip(*iters):
|
||||
pair = trycast(tuple[str, Any], pair)
|
||||
assert pair is not None
|
||||
print(pair[0])
|
||||
if pair[0] == 'text':
|
||||
line = Line()
|
||||
line.addFragment(
|
||||
Fragment(pair[1], r.textFont, color=r.baseColor)
|
||||
)
|
||||
lines.append(line)
|
||||
return (frags, lines)
|
||||
|
||||
def do_pseq(outer: int,
|
||||
inner: int,
|
||||
pseq: list[list[Pair]]| None ) -> tuple[list[Fragment], list[Line]]:
|
||||
assert pseq is not None
|
||||
lines: list[Line] = []
|
||||
frags: list[Fragment] = []
|
||||
for entry in pseq:
|
||||
pairs = make_pairs(entry)
|
||||
for pair in pairs:
|
||||
if pair['objType'] == 'bs':
|
||||
(newFrags, newLines) = do_sense(trycast(Sense, pair['obj']))
|
||||
frags += newFrags
|
||||
lines += newLines
|
||||
elif pair['objType'] == 'sense':
|
||||
(newFrags, newLines) = do_sense(trycast(Sense, pair['obj']))
|
||||
frags += newFrags
|
||||
lines += newLines
|
||||
else:
|
||||
raise Exception(f"Unknown object type {pair['objType']}")
|
||||
return (frags, lines)
|
||||
|
||||
def do_sseq(sseq:list[list[list[Pair]]]) -> list[Line]:
|
||||
lines: list[Line] = []
|
||||
r = Resources()
|
||||
for outer, item_o in enumerate(sseq):
|
||||
line = Line()
|
||||
line.addFragment(
|
||||
Fragment(str(outer+1), r.boldFont, color=r.baseColor)
|
||||
)
|
||||
for inner, item_i in enumerate(item_o):
|
||||
line.addFragment(
|
||||
Fragment(chr(ord('a')+inner), r.boldFont, color=r.baseColor)
|
||||
)
|
||||
pairs = make_pairs(item_i)
|
||||
for pair in pairs:
|
||||
objType = pair['objType']
|
||||
if objType == 'sense':
|
||||
sense = trycast(Sense, pair['obj'])
|
||||
(frags, newlines) = do_sense(sense)
|
||||
for frag in frags:
|
||||
line.addFragment(frag)
|
||||
lines.append(line)
|
||||
lines += newlines
|
||||
elif objType == 'sen':
|
||||
raise Exception(f"sen unimplimented")
|
||||
elif objType == 'pseq':
|
||||
pseq = trycast(list[list[Pair]], pair['obj'])
|
||||
(frags, newlines) = do_pseq(inner, outer, trycast(list[list[Pair]], pair['obj']))
|
||||
for frag in frags:
|
||||
line.addFragment(frag)
|
||||
lines.append(line)
|
||||
lines += newlines
|
||||
elif objType == 'bs':
|
||||
raise Exception(f"bs unimplimented")
|
||||
else:
|
||||
raise Exception(f"Unknown object[{objType}] for \n{json.dumps(pair['obj'],indent=2)}")
|
||||
return lines
|
||||
|
||||
def do_def(entry: Definition) -> list[Line]:
|
||||
r = Resources()
|
||||
lines: list[Line] = []
|
||||
assert trycast(Definition, entry) is not None
|
||||
if 'vd' in entry:
|
||||
line = Line()
|
||||
line.addFragment(
|
||||
Fragment(entry['vd'], r.italicFont, color = r.linkColor)
|
||||
)
|
||||
lines.append(line)
|
||||
#
|
||||
# sseg is required
|
||||
#
|
||||
sseq = entry['sseq']
|
||||
lines += do_sseq(sseq)
|
||||
return lines
|
||||
|
||||
def getDef(definition: list[Entry]) -> list[Line]:
|
||||
lines = []
|
||||
r = Resources()
|
||||
lines:list[Line] = []
|
||||
#
|
||||
# Pull the fonts for ease of use
|
||||
#
|
||||
headerFont = trycast(QFont, Word._resources['fonts']['header'])
|
||||
assert headerFont is not None
|
||||
textFont = trycast(QFont, Word._resources['fonts']['text'])
|
||||
assert textFont is not None
|
||||
labelFont = trycast(QFont, Word._resources['fonts']['label'])
|
||||
assert labelFont is not None
|
||||
headerFont = r.headerFont
|
||||
textFont = r.textFont
|
||||
labelFont = r.labelFont
|
||||
#
|
||||
# Pull the colors for ease of use
|
||||
#
|
||||
baseColor = trycast(QColor, Word._resources['colors']['base'])
|
||||
assert baseColor is not None
|
||||
linkColor = trycast(QColor, Word._resources['colors']['link'])
|
||||
assert linkColor is not None
|
||||
subduedColor = trycast(QColor, Word._resources['colors']['subdued'])
|
||||
assert subduedColor is not None
|
||||
baseColor = r.baseColor
|
||||
linkColor = r.linkColor
|
||||
subduedColor = r.subduedColor
|
||||
|
||||
#
|
||||
# No need to figure it out each time it is used
|
||||
#
|
||||
entries = 0
|
||||
id = definition[0]['meta']['id']
|
||||
id = ':'.split(id)[0].lower()
|
||||
id = definition[0]['meta']['id'].lower().split(':')[0]
|
||||
uses: dict[str,int] = {}
|
||||
for entry in definition:
|
||||
if entry['meta']['id'].lower() == id:
|
||||
testId = entry['meta']['id'].lower().split(':')[0]
|
||||
if testId == id:
|
||||
entries += 1
|
||||
try:
|
||||
uses[entry['fl']] = uses.get(entry['fl'], 0) + 1
|
||||
except KeyError:
|
||||
pass
|
||||
used: dict[str, int] = {}
|
||||
for k in uses.keys():
|
||||
used[k] = 0
|
||||
for count, entry in enumerate(definition):
|
||||
if entry['meta']['id'].lower() != id:
|
||||
testId = entry['meta']['id'].lower().split(':')[0]
|
||||
if testId != id:
|
||||
continue
|
||||
#
|
||||
# Create the First line from the hwi, [ahws] and fl
|
||||
@@ -270,13 +376,16 @@ def getDef(definition: list[Entry]) -> list[Line]:
|
||||
for ahw in ahws:
|
||||
hw = re.sub(r'\*', '', ahw['hw'])
|
||||
line.addFragment(Fragment(', ' + hw, headerFont, color=baseColor))
|
||||
if 'hom' in entry:
|
||||
|
||||
if entries > 1:
|
||||
frag = Fragment(f" {count + 1} of {entries} ", textFont, color= subduedColor)
|
||||
frag.setBackground(QColor(Qt.GlobalColor.gray))
|
||||
line.addFragment(frag)
|
||||
if 'fl' in entry:
|
||||
frag = Fragment(f"{count} of {entries} ", textFont, color=
|
||||
frag.setBackground(QColor(Qt.GlobalColor.gray))
|
||||
line.addFragment(frag)
|
||||
line.addFragment(Fragment(entry['fl'], labelFont, color=baseColor))
|
||||
text = entry['fl']
|
||||
used[text] += 1
|
||||
if uses[text] > 1:
|
||||
text += f' ({used[text]})'
|
||||
line.addFragment(Fragment(text, labelFont, color=baseColor))
|
||||
lines.append(line)
|
||||
|
||||
#
|
||||
@@ -284,11 +393,15 @@ def getDef(definition: list[Entry]) -> list[Line]:
|
||||
# While 'prs' is optional, the headword is not. This gets us what we want.
|
||||
#
|
||||
line = Line()
|
||||
hw = re.sub(r'\*', '\u00b7', hwi['hw'])
|
||||
line.addFragment(Fragment(hw + ' ', textFont, color=subduedColor))
|
||||
for frag in do_prs(hwi['prs']):
|
||||
if hwi['hw'].find('*') >= 0:
|
||||
hw = re.sub(r'\*', '\u00b7', hwi['hw'])
|
||||
line.addFragment(Fragment(hw + ' ', textFont, color=subduedColor))
|
||||
for frag in do_prs(hwi):
|
||||
line.addFragment(frag)
|
||||
|
||||
#
|
||||
# Try for
|
||||
return [Line()]
|
||||
if len(line.getLine()) > 0:
|
||||
lines.append(line)
|
||||
defines = trycast(list[Definition], entry['def'])
|
||||
assert defines is not None
|
||||
for define in defines:
|
||||
lines += do_def(define)
|
||||
return lines
|
||||
|
||||
Reference in New Issue
Block a user