From 9626b2d6117866d70e3e4749c4dcf89cb2a24cbc Mon Sep 17 00:00:00 2001 From: Pedro Revez Date: Mon, 4 Oct 2021 17:54:27 +0100 Subject: [PATCH] Black and isort --- jisho_api/__init__.py | 2 +- jisho_api/cli.py | 63 +++++----- jisho_api/kanji/cfg.py | 23 ++-- jisho_api/kanji/request.py | 219 +++++++++++++++++++++++----------- jisho_api/sentence/cfg.py | 2 +- jisho_api/sentence/request.py | 51 ++++---- jisho_api/util.py | 29 +++-- jisho_api/word/cfg.py | 8 +- jisho_api/word/request.py | 28 ++--- 9 files changed, 264 insertions(+), 161 deletions(-) diff --git a/jisho_api/__init__.py b/jisho_api/__init__.py index 5f8e6bd..a9463af 100644 --- a/jisho_api/__init__.py +++ b/jisho_api/__init__.py @@ -1,3 +1,3 @@ from rich.console import Console -console = Console() \ No newline at end of file +console = Console() diff --git a/jisho_api/cli.py b/jisho_api/cli.py index 18e9248..d8db751 100644 --- a/jisho_api/cli.py +++ b/jisho_api/cli.py @@ -1,17 +1,15 @@ import json -import click import pprint -from jisho_api.word.request import Word -from jisho_api.kanji.request import Kanji -from jisho_api.sentence.request import Sentence -from jisho_api import console - from pathlib import Path - +import click +from rich.progress import Progress, track from rich.prompt import Prompt -from rich.progress import track, Progress +from jisho_api import console +from jisho_api.kanji.request import Kanji +from jisho_api.sentence.request import Sentence +from jisho_api.word.request import Word @click.group() @@ -19,42 +17,46 @@ def main(): """A jisho.org API. Test the API, or search the Japanese dictionary.""" pass + @click.group() def search(): """Search jisho.org for words, kanjis, or sentences.""" pass + @click.group() def scrape(): """Scrape requests, given a list of search terms.""" pass + @click.command(name="config") def config(): """Set ~/.jisho/config.json with cache settings.""" val = click.confirm("Cache enabled?") - p = Path.home() / '.jisho' + p = Path.home() / ".jisho" p.mkdir(exist_ok=True) - with open(p / 'config.json', 'w') as fp: + with open(p / "config.json", "w") as fp: json.dump({"cache": val}, fp, indent=4) console.print("Config written to '.jisho/config.json'") + def _get_home_config(): - p = Path.home() / '.jisho/config.json' + p = Path.home() / ".jisho/config.json" if p.exists(): - with open(p, 'r') as fp: + with open(p, "r") as fp: return json.load(fp) else: return None + def _cache_enabled(): cfg = _get_home_config() if cfg: - return cfg['cache'] + return cfg["cache"] return False - def scraper(cls, words, root_dump, cache=True): words = {} with Progress(console=console, transient=True) as progress: @@ -62,12 +64,12 @@ def scraper(cls, words, root_dump, cache=True): for i, w in enumerate(words): # 0 - name should be between quotes to search specifically for it # with a * it is a wildcard, to see applications of this word at the end - strict = '*' not in w + strict = "*" not in w if strict: w = f'"{w}"' - + # 1 - if file exists do not request - word_path =root_dump / f'{w}.json' + word_path = root_dump / f"{w}.json" if word_path.exists(): progress.advance(task1) continue @@ -76,16 +78,17 @@ def scraper(cls, words, root_dump, cache=True): wr = cls.request(w, cache=cache) if wr is None: progress.advance(task1) - continue + continue words[w] = wr progress.advance(task1) return words + def _load_words(file_path): - with open(file_path, 'r') as fp: + with open(file_path, "r") as fp: txt = fp.read() - words = txt.split('\n') + words = txt.split("\n") return words @@ -97,6 +100,7 @@ def scrape_words(file_path: str): scraper(Word, _load_words(file_path), root_dump) + @click.command(name="kanji") @click.argument("file_path") def scrape_kanji(file_path: str): @@ -105,6 +109,7 @@ def scrape_kanji(file_path: str): scraper(Kanji, _load_words(file_path), root_dump) + @click.command(name="sentence") @click.argument("file_path") def scrape_sentence(file_path: str): @@ -113,36 +118,40 @@ def scrape_sentence(file_path: str): scraper(Sentence, _load_words(file_path), root_dump) + @click.command(name="word") @click.argument("word") -@click.option('--cache', type=bool, is_flag=True) -@click.option('--no-cache', type=bool, is_flag=True) +@click.option("--cache", type=bool, is_flag=True) +@click.option("--no-cache", type=bool, is_flag=True) def request_word(word: str, cache: bool, no_cache: bool): flag = (cache or _cache_enabled()) and not no_cache w = Word.request(word, cache=flag) if w: w.rich_print() + @click.command(name="kanji") @click.argument("kanji") -@click.option('--cache', type=bool, is_flag=True) -@click.option('--no-cache', type=bool, is_flag=True) +@click.option("--cache", type=bool, is_flag=True) +@click.option("--no-cache", type=bool, is_flag=True) def request_kanji(kanji: str, cache: bool, no_cache: bool): flag = (cache or _cache_enabled()) and not no_cache k = Kanji.request(kanji, cache=flag) if k: k.rich_print() + @click.command(name="sentence") @click.argument("sentence") -@click.option('--cache', type=bool, is_flag=True) -@click.option('--no-cache', type=bool, is_flag=True) +@click.option("--cache", type=bool, is_flag=True) +@click.option("--no-cache", type=bool, is_flag=True) def request_sentence(sentence: str, cache: bool, no_cache: bool): flag = (cache or _cache_enabled()) and not no_cache k = Sentence.request(sentence, cache=flag) if k: k.rich_print() + # ============= # ==== CLI ==== # ============= @@ -162,4 +171,4 @@ def make_cli(): if __name__ == "__main__": - make_cli() \ No newline at end of file + make_cli() diff --git a/jisho_api/kanji/cfg.py b/jisho_api/kanji/cfg.py index 63ad5d9..6d7f817 100644 --- a/jisho_api/kanji/cfg.py +++ b/jisho_api/kanji/cfg.py @@ -1,22 +1,26 @@ -from pydantic import BaseModel, HttpUrl -from typing import List, Optional, Dict from enum import Enum +from typing import Dict, List, Optional + +from pydantic import BaseModel, HttpUrl +from rich.markdown import Markdown + from jisho_api import console from jisho_api.util import CLITagger -from rich.markdown import Markdown + class JLPT(str, Enum): - N5 = 'N5' - N4 = 'N4' - N3 = 'N3' - N2 = 'N2' - N1 = 'N1' + N5 = "N5" + N4 = "N4" + N3 = "N3" + N2 = "N2" + N1 = "N1" class MainReadings(BaseModel): kun: Optional[List[str]] on: Optional[List[str]] + class KanjiRadical(BaseModel): alt_forms: Optional[List[str]] meaning: str @@ -36,7 +40,7 @@ class KanjiMetaReadings(BaseModel): japanese: Optional[List[str]] chinese: Optional[List[str]] korean: Optional[List[str]] - + education: Optional[KanjiMetaEducation] dictionary_idxs: Dict[str, str] classifications: Dict[str, str] @@ -49,6 +53,7 @@ class Example(BaseModel): kanji: str reading: str meanings: List[str] + kun: Optional[List[Example]] on: Optional[List[Example]] diff --git a/jisho_api/kanji/request.py b/jisho_api/kanji/request.py index 60be3c2..df1fa96 100644 --- a/jisho_api/kanji/request.py +++ b/jisho_api/kanji/request.py @@ -1,20 +1,24 @@ -from pydantic import BaseModel, ValidationError -from pathlib import Path -import re import json import pprint +import re import urllib +from pathlib import Path + import requests -from .cfg import KanjiConfig from bs4 import BeautifulSoup +from pydantic import BaseModel, ValidationError +from rich.markdown import Markdown from jisho_api import console from jisho_api.util import CLITagger -from rich.markdown import Markdown + +from .cfg import KanjiConfig + class RequestMeta(BaseModel): status: int + class KanjiRequest(BaseModel): meta: RequestMeta data: KanjiConfig @@ -24,70 +28,124 @@ def __len__(self): def rich_print(self): base = f"[green]{self.data.kanji} " - base += CLITagger.colorize('Kun', ', '.join(self.data.main_readings.kun), 'red',) - base += CLITagger.colorize('On', ', '.join(self.data.main_readings.on), 'red', last=True) + base += CLITagger.colorize( + "Kun", + ", ".join(self.data.main_readings.kun), + "red", + ) + base += CLITagger.colorize( + "On", ", ".join(self.data.main_readings.on), "red", last=True + ) console.print(base) # TODO - TRY on this - base = CLITagger.colorize('Strokes', self.data.strokes, 'yellow') + base = CLITagger.colorize("Strokes", self.data.strokes, "yellow") try: - base += CLITagger.colorize('JLPT', self.data.meta.education.jlpt, 'magenta') - base += CLITagger.colorize('Grade', self.data.meta.education.grade, 'magenta', last=True) + base += CLITagger.colorize("JLPT", self.data.meta.education.jlpt, "magenta") + base += CLITagger.colorize( + "Grade", self.data.meta.education.grade, "magenta", last=True + ) except Exception as e: print(e) console.print(base) console.print(f"Radical no {self.data.radical.kangxi_order}:") - console.print(CLITagger.colorize('Base', f"{self.data.radical.basis} - {self.data.radical.meaning}", 'yellow', last=True)) + console.print( + CLITagger.colorize( + "Base", + f"{self.data.radical.basis} - {self.data.radical.meaning}", + "yellow", + last=True, + ) + ) try: - console.print(CLITagger.colorize('Alternate Radical', ', '.join(self.data.radical.alt_forms), 'yellow', last=True)) + console.print( + CLITagger.colorize( + "Alternate Radical", + ", ".join(self.data.radical.alt_forms), + "yellow", + last=True, + ) + ) except Exception as e: pass - console.print(CLITagger.colorize('Parts', ', '.join(self.data.radical.parts), 'yellow', last=True)) + console.print( + CLITagger.colorize( + "Parts", ", ".join(self.data.radical.parts), "yellow", last=True + ) + ) try: - console.print(CLITagger.colorize('Variants', ', '.join(self.data.radical.variants), 'yellow', last=True)) + console.print( + CLITagger.colorize( + "Variants", + ", ".join(self.data.radical.variants), + "yellow", + last=True, + ) + ) except Exception as e: pass - console.print() console.print("On Examples:") for m in self.data.reading_examples.on: - bullet_text = f"{m.kanji} [yellow][{m.reading}] [white]{', '.join(m.meanings)}" - console.print(CLITagger.bullet(bullet_text, color='green')) + bullet_text = ( + f"{m.kanji} [yellow][{m.reading}] [white]{', '.join(m.meanings)}" + ) + console.print(CLITagger.bullet(bullet_text, color="green")) console.print() console.print("Kun Examples:") for m in self.data.reading_examples.kun: - bullet_text = f"{m.kanji} [yellow][{m.reading}] [white]{', '.join(m.meanings)}" - console.print(CLITagger.bullet(bullet_text, color='green')) + bullet_text = ( + f"{m.kanji} [yellow][{m.reading}] [white]{', '.join(m.meanings)}" + ) + console.print(CLITagger.bullet(bullet_text, color="green")) class Kanji: - URL = 'https://jisho.org/search/' - ROOT = Path.home() / '.jisho/data/kanji/' + URL = "https://jisho.org/search/" + ROOT = Path.home() / ".jisho/data/kanji/" @staticmethod def strokes(soup): - return soup.find_all("div", {"class": "kanji-details__stroke_count"})[0].find('strong').text + return ( + soup.find_all("div", {"class": "kanji-details__stroke_count"})[0] + .find("strong") + .text + ) @staticmethod def main_meanings(soup): - return soup.find_all("div", {"class": "kanji-details__main-meanings"})[0].text.strip().split(', ') + return ( + soup.find_all("div", {"class": "kanji-details__main-meanings"})[0] + .text.strip() + .split(", ") + ) @staticmethod def main_readings(soup): res = soup.find_all("div", {"class": "kanji-details__main-readings"}) try: - kun = res[0].find_all("dl", {"class": "dictionary_entry kun_yomi"})[0].text.replace('\n', '').replace('Kun:', '').split('、 ') - except: + kun = ( + res[0] + .find_all("dl", {"class": "dictionary_entry kun_yomi"})[0] + .text.replace("\n", "") + .replace("Kun:", "") + .split("、 ") + ) + except: kun = None try: - on = res[0].find_all("dl", {"class": "dictionary_entry on_yomi"})[0].text.replace('\n', '').replace('On:', '').split('、 ') + on = ( + res[0] + .find_all("dl", {"class": "dictionary_entry on_yomi"})[0] + .text.replace("\n", "") + .replace("On:", "") + .split("、 ") + ) except: on = None - return { - "kun": kun, "on": on - } + return {"kun": kun, "on": on} @staticmethod def meta(soup): @@ -98,16 +156,15 @@ def meta(soup): "classifications": Kanji.meta_classifications(soup), "codepoints": Kanji.meta_codepoints(soup), "readings": Kanji.meta_readings(soup), - } @staticmethod def _scrape_table(table): - refs = table.find_all("td", {"class":"dic_ref"}) - names = table.find_all("td", {"class":"dic_name"}) + refs = table.find_all("td", {"class": "dic_ref"}) + names = table.find_all("td", {"class": "dic_name"}) refs = [r.text.strip() for r in refs] names = [n.text.strip() for n in names] - return {r:n for r, n in zip(refs, names)} + return {r: n for r, n in zip(refs, names)} @staticmethod def meta_dictionary_idxs(soup): @@ -118,29 +175,34 @@ def meta_dictionary_idxs(soup): def meta_classifications(soup): res = soup.find_all("section", {"id": "classifications"}) return Kanji._scrape_table(res[0]) + @staticmethod def meta_codepoints(soup): res = soup.find_all("section", {"id": "codepoints"}) return Kanji._scrape_table(res[0]) - @staticmethod def meta_readings(soup): res = soup.find_all("div", {"class": "kanji-details__readings row"}) try: - ja = res[0].find_all("dd", {"lang": "ja"})[0].text.split(', ') + ja = res[0].find_all("dd", {"lang": "ja"})[0].text.split(", ") except: ja = None try: cn = res[0].find_all("dl", {"class": "dictionary_entry pinyin"})[0] - cn = cn.find_all('dd')[0].text - cn = cn.split(', ') + cn = cn.find_all("dd")[0].text + cn = cn.split(", ") except: cn = None try: - kr = res[0].find_all("dl", {"class": "dictionary_entry korean"})[0].find_all('dd')[0].text.split(', ') + kr = ( + res[0] + .find_all("dl", {"class": "dictionary_entry korean"})[0] + .find_all("dd")[0] + .text.split(", ") + ) except: kr = None @@ -152,20 +214,26 @@ def meta_readings(soup): @staticmethod def meta_education(soup): - res = soup.find_all("div", {"class": "kanji_stats"})[0]#.find_all("strong") + res = soup.find_all("div", {"class": "kanji_stats"})[0] # .find_all("strong") try: - grade = res.find_all('div', {"class": "grade"})[0].find_all("strong").text.split(' ')[-1] + grade = ( + res.find_all("div", {"class": "grade"})[0] + .find_all("strong") + .text.split(" ")[-1] + ) except: grade = None try: - jlpt = res.find_all('div', {"class": "jlpt"})[0].find_all("strong").text + jlpt = res.find_all("div", {"class": "jlpt"})[0].find_all("strong").text except: jlpt = None try: - frequency = res.find_all('div', {"class": "frequency"})[0].find_all("strong").text + frequency = ( + res.find_all("div", {"class": "frequency"})[0].find_all("strong").text + ) except: frequency = None @@ -174,14 +242,18 @@ def meta_education(soup): @staticmethod def reading_examples(soup): try: - threeway = lambda x: (x[:x.index('【')], x[x.index('【')+1:x.index('】')], x[x.index('】')+1:]) + threeway = lambda x: ( + x[: x.index("【")], + x[x.index("【") + 1 : x.index("】")], + x[x.index("】") + 1 :], + ) process = lambda x: [ - { - "kanji": k.replace('\n', '').strip(), - "reading": r.replace('\n', '').strip(), - "meanings": m.replace('\n', '').strip().split(', ') - } - for k, r, m in x + { + "kanji": k.replace("\n", "").strip(), + "reading": r.replace("\n", "").strip(), + "meanings": m.replace("\n", "").strip().split(", "), + } + for k, r, m in x ] res = soup.find_all("ul", {"class": "no-bullet"}) @@ -204,31 +276,35 @@ def reading_examples(soup): @staticmethod def radical(soup): try: - variants = soup.find_all("dl", {"class": "dictionary_entry variants"})[0].find('a').text.split(' ') + variants = ( + soup.find_all("dl", {"class": "dictionary_entry variants"})[0] + .find("a") + .text.split(" ") + ) except: variants = None res = soup.find_all("div", {"class": "radicals"}) - parts = res[1].find_all('a') + parts = res[1].find_all("a") parts = [p.text for p in parts] rad = res[0] rad = rad.find_all("span") - rad_span = re.sub(' +', ' ', rad[0].text.replace('\n', '')).strip() - if '(' in rad_span and ')' in rad_span: - prn_idx = rad_span.index('(') + rad_span = re.sub(" +", " ", rad[0].text.replace("\n", "")).strip() + if "(" in rad_span and ")" in rad_span: + prn_idx = rad_span.index("(") rad_span_left = rad_span[:prn_idx] - rad_span_right = rad_span[prn_idx+1:-1] - rad_alt_form = rad_span_right.split(', ') + rad_span_right = rad_span[prn_idx + 1 : -1] + rad_alt_form = rad_span_right.split(", ") else: rad_span_left = rad_span rad_alt_form = None - rad_span_left = rad_span_left.strip().split(' ') + rad_span_left = rad_span_left.strip().split(" ") rad_meaning = rad_span_left[0] rad_basis = rad_span_left[-1] - rad_no = rad[0]['title'].split(' ')[-1][:-1] + rad_no = rad[0]["title"].split(" ")[-1][:-1] if not rad_no.isdigit(): rad_no = None @@ -238,22 +314,22 @@ def radical(soup): "basis": rad_basis, "kangxi_order": rad_no, "variants": variants, - "parts": parts + "parts": parts, } @staticmethod def request(kanji, cache=False): - url = Kanji.URL + urllib.parse.quote(kanji+" #kanji") + url = Kanji.URL + urllib.parse.quote(kanji + " #kanji") toggle = False - if cache and (Kanji.ROOT / (kanji+'.json')).exists(): + if cache and (Kanji.ROOT / (kanji + ".json")).exists(): toggle = True - with open(Kanji.ROOT / (kanji+'.json'), 'r') as fp: + with open(Kanji.ROOT / (kanji + ".json"), "r") as fp: r = json.load(fp) else: r = requests.get(url).content - - soup = BeautifulSoup(r, 'html.parser') + + soup = BeautifulSoup(r, "html.parser") try: r = { @@ -261,19 +337,20 @@ def request(kanji, cache=False): "status": 200, }, "data": { - "kanji": kanji, - "strokes":Kanji.strokes(soup), + "kanji": kanji, + "strokes": Kanji.strokes(soup), "main_meanings": Kanji.main_meanings(soup), "main_readings": Kanji.main_readings(soup), "meta": Kanji.meta(soup), "radical": Kanji.radical(soup), - "reading_examples": Kanji.reading_examples(soup) - } - + "reading_examples": Kanji.reading_examples(soup), + }, } r = KanjiRequest(**r) except Exception as e: - console.print(f"[red bold ][Error][/red bold] [white]No kanji found with name {kanji}.") + console.print( + f"[red bold ][Error][/red bold] [white]No kanji found with name {kanji}." + ) return None if cache and not toggle: Kanji.save(kanji, r) @@ -282,5 +359,5 @@ def request(kanji, cache=False): @staticmethod def save(word, r): Kanji.ROOT.mkdir(exist_ok=True) - with open(Kanji.ROOT / f"{word}.json", 'w') as fp: + with open(Kanji.ROOT / f"{word}.json", "w") as fp: json.dump(r.dict(), fp, indent=4, ensure_ascii=False) diff --git a/jisho_api/sentence/cfg.py b/jisho_api/sentence/cfg.py index 74e8a0a..7a75ec5 100644 --- a/jisho_api/sentence/cfg.py +++ b/jisho_api/sentence/cfg.py @@ -3,4 +3,4 @@ class SentenceConfig(BaseModel): japanese: str - en_translation: str \ No newline at end of file + en_translation: str diff --git a/jisho_api/sentence/request.py b/jisho_api/sentence/request.py index e3cdb5c..71a44ad 100644 --- a/jisho_api/sentence/request.py +++ b/jisho_api/sentence/request.py @@ -1,21 +1,25 @@ -from pydantic import BaseModel, ValidationError -from pathlib import Path import json -import re import pprint +import re import urllib -import requests +from pathlib import Path from typing import List + +import requests from bs4 import BeautifulSoup +from pydantic import BaseModel, ValidationError +from rich.markdown import Markdown from jisho_api import console from jisho_api.util import CLITagger -from rich.markdown import Markdown + from .cfg import SentenceConfig + class RequestMeta(BaseModel): status: int + class SentenceRequest(BaseModel): meta: RequestMeta data: List[SentenceConfig] @@ -29,57 +33,54 @@ def rich_print(self): console.print(CLITagger.bullet(d.japanese)) console.print(f"[white][[blue]en[white]]") console.print(CLITagger.bullet(d.en_translation)) - console.print(Markdown('---')) + console.print(Markdown("---")) class Sentence: - URL = 'https://jisho.org/search/' - ROOT = Path.home() / '.jisho/data/sentence/' + URL = "https://jisho.org/search/" + ROOT = Path.home() / ".jisho/data/sentence/" @staticmethod def sentences(soup): - res = soup.find_all('div', {"class": "sentence_content"}) + res = soup.find_all("div", {"class": "sentence_content"}) sts = [] for r in res: - s1_jp = r.find_all('li') - s1_en = r.find_all('span', {"class": "english"})[0].text + s1_jp = r.find_all("li") + s1_en = r.find_all("span", {"class": "english"})[0].text b = "" - for s in s1_jp: - u = s.find('span', {"class": "unlinked"}).text + for s in s1_jp: + u = s.find("span", {"class": "unlinked"}).text b += u try: - f = s.find('span', {"class": "furigana"}).text + f = s.find("span", {"class": "furigana"}).text b += f"({f})" except: pass - sts.append({ - "japanese": b, - "en_translation": s1_en - }) + sts.append({"japanese": b, "en_translation": s1_en}) return sts @staticmethod def request(word, cache=False): - url = Sentence.URL + urllib.parse.quote(word+" #sentences") + url = Sentence.URL + urllib.parse.quote(word + " #sentences") toggle = False - if cache and (Sentence.ROOT / (word+'.json')).exists(): + if cache and (Sentence.ROOT / (word + ".json")).exists(): toggle = True - with open(Sentence.ROOT / (word+'.json'), 'r') as fp: + with open(Sentence.ROOT / (word + ".json"), "r") as fp: r = json.load(fp) else: r = requests.get(url).content - soup = BeautifulSoup(r, 'html.parser') + soup = BeautifulSoup(r, "html.parser") r = SentenceRequest( **{ "meta": { "status": 200, }, - "data": Sentence.sentences(soup) + "data": Sentence.sentences(soup), } ) if not len(r): @@ -92,5 +93,5 @@ def request(word, cache=False): @staticmethod def save(word, r): Sentence.ROOT.mkdir(exist_ok=True) - with open(Sentence.ROOT / f"{word}.json", 'w') as fp: - json.dump(r.dict(), fp, indent=4, ensure_ascii=False) \ No newline at end of file + with open(Sentence.ROOT / f"{word}.json", "w") as fp: + json.dump(r.dict(), fp, indent=4, ensure_ascii=False) diff --git a/jisho_api/util.py b/jisho_api/util.py index b1fc4df..a675d88 100644 --- a/jisho_api/util.py +++ b/jisho_api/util.py @@ -4,35 +4,44 @@ def colorize(tag, value, color, last=False): base = f"[{color}][{tag}: [white]{value}[{color}]]" if not last: base += " [white]| " - return base + return base @staticmethod - def bullet(text, color='white'): + def bullet(text, color="white"): return f"[yellow]• [{color}]{text}" -def flatten_recur(dct, rdct={}, separator='.', parent=''): + +def flatten_recur(dct, rdct={}, separator=".", parent=""): for k, v in dct.items(): if isinstance(v, list): if len(v) > 0 and isinstance(v[0], dict): for i, l in enumerate(v): - flatten_recur(l, rdct, parent=f"{parent}{k}{separator}{i}{separator}", separator=separator) + flatten_recur( + l, + rdct, + parent=f"{parent}{k}{separator}{i}{separator}", + separator=separator, + ) else: rdct[parent + k] = v elif not isinstance(v, dict): rdct[parent + k] = v else: - flatten_recur(v, rdct, separator=separator, parent=f"{parent}{k}{separator}") + flatten_recur( + v, rdct, separator=separator, parent=f"{parent}{k}{separator}" + ) return rdct -def deflatten_recur(dct, rdct={}, separator='.'): - for k, v in dct.items(): + +def deflatten_recur(dct, rdct={}, separator="."): + for k, v in dct.items(): toks = k.split(separator) if len(toks) == 1: rdct[k] = v else: p = toks[0] toks = toks[1:] - + if toks[0].isdigit(): idx = int(toks[0]) # list @@ -40,7 +49,7 @@ def deflatten_recur(dct, rdct={}, separator='.'): rdct[p] = [] if len(rdct[p]) == idx: rdct[p].append({}) - + d = {separator.join(toks[1:]): v} deflatten_recur(d, rdct[p][idx], separator=separator) @@ -52,4 +61,4 @@ def deflatten_recur(dct, rdct={}, separator='.'): d = {toks: v} deflatten_recur(d, rdct[p], separator=separator) - return rdct \ No newline at end of file + return rdct diff --git a/jisho_api/word/cfg.py b/jisho_api/word/cfg.py index efd4f63..29b119e 100644 --- a/jisho_api/word/cfg.py +++ b/jisho_api/word/cfg.py @@ -1,6 +1,7 @@ -from pydantic import BaseModel, HttpUrl -from typing import List, Optional from enum import Enum +from typing import List, Optional + +from pydantic import BaseModel, HttpUrl class Sense(BaseModel): @@ -10,6 +11,7 @@ class Link(BaseModel): class Source(BaseModel): language: str + english_definitions: List[str] parts_of_speech: List[Optional[str]] links: List[Link] @@ -45,4 +47,4 @@ class WordConfig(BaseModel): senses: List[Sense] def __iter__(self): - yield from self.senses \ No newline at end of file + yield from self.senses diff --git a/jisho_api/word/request.py b/jisho_api/word/request.py index 18623e1..152f6fd 100644 --- a/jisho_api/word/request.py +++ b/jisho_api/word/request.py @@ -1,23 +1,22 @@ -import requests import json import pprint import urllib -from pydantic import ValidationError, validator from pathlib import Path - -from pydantic import BaseModel from typing import List -from .cfg import WordConfig -from jisho_api import console - +import requests +from pydantic import BaseModel, ValidationError, validator from rich.markdown import Markdown +from jisho_api import console + +from .cfg import WordConfig class RequestMeta(BaseModel): status: int + class WordRequest(BaseModel): meta: RequestMeta data: List[WordConfig] @@ -48,7 +47,7 @@ def rich_print(self): else: base += f", [purple]{j.reading}" - if len(wdef.jlpt) : + if len(wdef.jlpt): base += f" [blue][JLPT: {', '.join(wdef.jlpt)}]" console.print(base) @@ -56,20 +55,21 @@ def rich_print(self): base = f"[yellow]{i+1}. [white]{', '.join(s.english_definitions)}" base += "".join([f", ([magenta]{t}[white])" for t in s.tags]) console.print(base) - console.print(Markdown('---')) + console.print(Markdown("---")) + class Word: - URL = 'https://jisho.org/api/v1/search/words?keyword=' - ROOT = Path.home() / '.jisho/data/word' + URL = "https://jisho.org/api/v1/search/words?keyword=" + ROOT = Path.home() / ".jisho/data/word" @staticmethod def request(word, cache=False): url = Word.URL + urllib.parse.quote(word) toggle = False - if cache and (Word.ROOT / (word+'.json')).exists(): + if cache and (Word.ROOT / (word + ".json")).exists(): toggle = True - with open(Word.ROOT / (word+'.json'), 'r') as fp: + with open(Word.ROOT / (word + ".json"), "r") as fp: r = json.load(fp) else: r = requests.get(url).json() @@ -85,5 +85,5 @@ def request(word, cache=False): @staticmethod def save(word, r): Word.ROOT.mkdir(exist_ok=True) - with open(Word.ROOT / f"{word}.json", 'w') as fp: + with open(Word.ROOT / f"{word}.json", "w") as fp: fp.write(json.dumps(r.dict(), indent=4, ensure_ascii=False))