From 6c457d406eb434ea5044d907de3eacee2616b53a Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 4 Feb 2026 08:08:33 +0000
Subject: [PATCH 01/17] Initial plan
From 2f5fd31c252bc0cfbace249ebdd1bf33d252127d Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 4 Feb 2026 08:10:09 +0000
Subject: [PATCH 02/17] Initial type annotation progress check
Co-authored-by: bact <128572+bact@users.noreply.github.com>
---
.../output/class_variables_no_hints.csv | 2 +
.../output/functions_incomplete_hints.csv | 2 +-
.../analysis/output/functions_no_hints.csv | 2 +-
.../output/instance_variables_no_hints.csv | 210 +++++++++++++
.../output/module_variables_no_hints.csv | 296 ++++++++++++++++++
.../analysis/output/submodule_summary.csv | 56 ++--
build_tools/analysis/output/type_aliases.csv | 1 +
.../analysis/output/type_hint_analysis.json | 120 +++----
8 files changed, 606 insertions(+), 83 deletions(-)
create mode 100644 build_tools/analysis/output/class_variables_no_hints.csv
create mode 100644 build_tools/analysis/output/instance_variables_no_hints.csv
create mode 100644 build_tools/analysis/output/module_variables_no_hints.csv
create mode 100644 build_tools/analysis/output/type_aliases.csv
diff --git a/build_tools/analysis/output/class_variables_no_hints.csv b/build_tools/analysis/output/class_variables_no_hints.csv
new file mode 100644
index 000000000..4ddea9cd2
--- /dev/null
+++ b/build_tools/analysis/output/class_variables_no_hints.csv
@@ -0,0 +1,2 @@
+Variable Name,Submodule,Parent Class,Scope,File,Line
+pythainlp.util.trie.Node.__slots__,util,Node,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/trie.py,53
diff --git a/build_tools/analysis/output/functions_incomplete_hints.csv b/build_tools/analysis/output/functions_incomplete_hints.csv
index 26d33430d..16eec6f10 100644
--- a/build_tools/analysis/output/functions_incomplete_hints.csv
+++ b/build_tools/analysis/output/functions_incomplete_hints.csv
@@ -1 +1 @@
-Function Name,Submodule,Scope,Priority,Params Hinted,Has Return,References,Test Suite,File,Line
+Function Name,Submodule,Scope,Priority,Params Hinted,Has Return,References,Test Suite,Decorators,File,Line
diff --git a/build_tools/analysis/output/functions_no_hints.csv b/build_tools/analysis/output/functions_no_hints.csv
index 4b3e89e07..a0f2e30c4 100644
--- a/build_tools/analysis/output/functions_no_hints.csv
+++ b/build_tools/analysis/output/functions_no_hints.csv
@@ -1 +1 @@
-Function Name,Submodule,Scope,Priority,References,Test Suite,File,Line
+Function Name,Submodule,Scope,Priority,References,Test Suite,Decorators,File,Line
diff --git a/build_tools/analysis/output/instance_variables_no_hints.csv b/build_tools/analysis/output/instance_variables_no_hints.csv
new file mode 100644
index 000000000..7b512c5bb
--- /dev/null
+++ b/build_tools/analysis/output/instance_variables_no_hints.csv
@@ -0,0 +1,210 @@
+Variable Name,Submodule,Parent Class,Scope,File,Line
+pythainlp.augment.lm.fasttext.FastTextAug.model,augment,FastTextAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/lm/fasttext.py,35
+pythainlp.augment.lm.fasttext.FastTextAug.model,augment,FastTextAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/lm/fasttext.py,37
+pythainlp.augment.lm.phayathaibert.ThaiTextAugmenter.tokenizer,augment,ThaiTextAugmenter,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/lm/phayathaibert.py,31
+pythainlp.augment.lm.phayathaibert.ThaiTextAugmenter.model_for_masked_lm,augment,ThaiTextAugmenter,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/lm/phayathaibert.py,32
+pythainlp.augment.lm.phayathaibert.ThaiTextAugmenter.model,augment,ThaiTextAugmenter,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/lm/phayathaibert.py,35
+pythainlp.augment.lm.phayathaibert.ThaiTextAugmenter.processor,augment,ThaiTextAugmenter,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/lm/phayathaibert.py,40
+pythainlp.augment.lm.wangchanberta.Thai2transformersAug.model_name,augment,Thai2transformersAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/lm/wangchanberta.py,28
+pythainlp.augment.lm.wangchanberta.Thai2transformersAug.target_tokenizer,augment,Thai2transformersAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/lm/wangchanberta.py,29
+pythainlp.augment.lm.wangchanberta.Thai2transformersAug.tokenizer,augment,Thai2transformersAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/lm/wangchanberta.py,30
+pythainlp.augment.lm.wangchanberta.Thai2transformersAug.fill_mask,augment,Thai2transformersAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/lm/wangchanberta.py,38
+pythainlp.augment.lm.wangchanberta.Thai2transformersAug.MASK_TOKEN,augment,Thai2transformersAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/lm/wangchanberta.py,44
+pythainlp.augment.lm.wangchanberta.Thai2transformersAug.input_text,augment,Thai2transformersAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/lm/wangchanberta.py,50
+pythainlp.augment.word2vec.bpemb_wv.BPEmbAug.bpemb_temp,augment,BPEmbAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/word2vec/bpemb_wv.py,35
+pythainlp.augment.word2vec.bpemb_wv.BPEmbAug.model,augment,BPEmbAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/word2vec/bpemb_wv.py,36
+pythainlp.augment.word2vec.bpemb_wv.BPEmbAug.aug,augment,BPEmbAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/word2vec/bpemb_wv.py,47
+pythainlp.augment.word2vec.bpemb_wv.BPEmbAug.sentence,augment,BPEmbAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/word2vec/bpemb_wv.py,71
+pythainlp.augment.word2vec.bpemb_wv.BPEmbAug.temp,augment,BPEmbAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/word2vec/bpemb_wv.py,72
+pythainlp.augment.word2vec.bpemb_wv.BPEmbAug.temp_new,augment,BPEmbAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/word2vec/bpemb_wv.py,73
+pythainlp.augment.word2vec.bpemb_wv.BPEmbAug.t,augment,BPEmbAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/word2vec/bpemb_wv.py,75
+pythainlp.augment.word2vec.core.Word2VecAug.model,augment,Word2VecAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/word2vec/core.py,34
+pythainlp.augment.word2vec.core.Word2VecAug.model,augment,Word2VecAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/word2vec/core.py,38
+pythainlp.augment.word2vec.ltw2v.LTW2VAug.ltw2v_wv,augment,LTW2VAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/word2vec/ltw2v.py,30
+pythainlp.augment.word2vec.ltw2v.LTW2VAug.aug,augment,LTW2VAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/word2vec/ltw2v.py,46
+pythainlp.augment.word2vec.thai2fit.Thai2fitAug.thai2fit_wv,augment,Thai2fitAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/word2vec/thai2fit.py,30
+pythainlp.augment.word2vec.thai2fit.Thai2fitAug.aug,augment,Thai2fitAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/word2vec/thai2fit.py,47
+pythainlp.augment.wordnet.WordNetAug.list_synsets,augment,WordNetAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/wordnet.py,140
+pythainlp.augment.wordnet.WordNetAug.p2w_pos,augment,WordNetAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/wordnet.py,142
+pythainlp.augment.wordnet.WordNetAug.list_synsets,augment,WordNetAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/wordnet.py,144
+pythainlp.augment.wordnet.WordNetAug.list_synsets,augment,WordNetAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/wordnet.py,146
+pythainlp.augment.wordnet.WordNetAug.temp,augment,WordNetAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/wordnet.py,205
+pythainlp.chat.core.ChatBotModel.history,chat,ChatBotModel,public,/home/runner/work/pythainlp/pythainlp/pythainlp/chat/core.py,16
+pythainlp.chat.core.ChatBotModel.model,chat,ChatBotModel,public,/home/runner/work/pythainlp/pythainlp/pythainlp/chat/core.py,41
+pythainlp.classify.param_free.GzipModel.training_data,classify,GzipModel,public,/home/runner/work/pythainlp/pythainlp/pythainlp/classify/param_free.py,36
+pythainlp.classify.param_free.GzipModel.cx2_list,classify,GzipModel,public,/home/runner/work/pythainlp/pythainlp/pythainlp/classify/param_free.py,37
+pythainlp.classify.param_free.GzipModel.cx2_list,classify,GzipModel,public,/home/runner/work/pythainlp/pythainlp/pythainlp/classify/param_free.py,109
+pythainlp.classify.param_free.GzipModel.training_data,classify,GzipModel,public,/home/runner/work/pythainlp/pythainlp/pythainlp/classify/param_free.py,110
+pythainlp.cli.tag.SubAppBase.args,cli,SubAppBase,public,/home/runner/work/pythainlp/pythainlp/pythainlp/cli/tag.py,41
+pythainlp.cli.tag.POSTaggingApp.separator,cli,POSTaggingApp,public,/home/runner/work/pythainlp/pythainlp/pythainlp/cli/tag.py,55
+pythainlp.cli.tag.POSTaggingApp.run,cli,POSTaggingApp,public,/home/runner/work/pythainlp/pythainlp/pythainlp/cli/tag.py,56
+pythainlp.cli.tokenize.SubAppBase.args,cli,SubAppBase,public,/home/runner/work/pythainlp/pythainlp/pythainlp/cli/tokenize.py,77
+pythainlp.corpus.core._ResponseWrapper.status_code,corpus,_ResponseWrapper,public,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/core.py,41
+pythainlp.corpus.core._ResponseWrapper.headers,corpus,_ResponseWrapper,public,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/core.py,42
+pythainlp.corpus.core._ResponseWrapper._content,corpus,_ResponseWrapper,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/core.py,43
+pythainlp.el._multiel.MultiEL.model_name,el,MultiEL,public,/home/runner/work/pythainlp/pythainlp/pythainlp/el/_multiel.py,18
+pythainlp.el._multiel.MultiEL.device,el,MultiEL,public,/home/runner/work/pythainlp/pythainlp/pythainlp/el/_multiel.py,19
+pythainlp.el._multiel.MultiEL._bela_run,el,MultiEL,private,/home/runner/work/pythainlp/pythainlp/pythainlp/el/_multiel.py,29
+pythainlp.generate.core.Unigram.counts,generate,Unigram,public,/home/runner/work/pythainlp/pythainlp/pythainlp/generate/core.py,43
+pythainlp.generate.core.Unigram.counts,generate,Unigram,public,/home/runner/work/pythainlp/pythainlp/pythainlp/generate/core.py,45
+pythainlp.generate.core.Unigram._word_prob,generate,Unigram,private,/home/runner/work/pythainlp/pythainlp/pythainlp/generate/core.py,83
+pythainlp.spell.words_spelling_correction.FastTextEncoder.model_dir,spell,FastTextEncoder,public,/home/runner/work/pythainlp/pythainlp/pythainlp/spell/words_spelling_correction.py,68
+pythainlp.spell.words_spelling_correction.FastTextEncoder.nn_model_path,spell,FastTextEncoder,public,/home/runner/work/pythainlp/pythainlp/pythainlp/spell/words_spelling_correction.py,69
+pythainlp.spell.words_spelling_correction.FastTextEncoder.bucket,spell,FastTextEncoder,public,/home/runner/work/pythainlp/pythainlp/pythainlp/spell/words_spelling_correction.py,70
+pythainlp.spell.words_spelling_correction.FastTextEncoder.nb_words,spell,FastTextEncoder,public,/home/runner/work/pythainlp/pythainlp/pythainlp/spell/words_spelling_correction.py,71
+pythainlp.spell.words_spelling_correction.FastTextEncoder.minn,spell,FastTextEncoder,public,/home/runner/work/pythainlp/pythainlp/pythainlp/spell/words_spelling_correction.py,72
+pythainlp.spell.words_spelling_correction.FastTextEncoder.maxn,spell,FastTextEncoder,public,/home/runner/work/pythainlp/pythainlp/pythainlp/spell/words_spelling_correction.py,73
+pythainlp.spell.words_spelling_correction.FastTextEncoder.words_for_suggestion,spell,FastTextEncoder,public,/home/runner/work/pythainlp/pythainlp/pythainlp/spell/words_spelling_correction.py,77
+pythainlp.spell.words_spelling_correction.FastTextEncoder.nn_session,spell,FastTextEncoder,public,/home/runner/work/pythainlp/pythainlp/pythainlp/spell/words_spelling_correction.py,78
+pythainlp.spell.words_spelling_correction.Words_Spelling_Correction.list_word,spell,Words_Spelling_Correction,public,/home/runner/work/pythainlp/pythainlp/pythainlp/spell/words_spelling_correction.py,267
+pythainlp.summarize.keybert.KeyBERT.ft_pipeline,summarize,KeyBERT,public,/home/runner/work/pythainlp/pythainlp/pythainlp/summarize/keybert.py,34
+pythainlp.tag._tag_perceptron.PerceptronTagger.tagdict,tag,PerceptronTagger,public,/home/runner/work/pythainlp/pythainlp/pythainlp/tag/_tag_perceptron.py,221
+pythainlp.tag._tag_perceptron.PerceptronTagger.classes,tag,PerceptronTagger,public,/home/runner/work/pythainlp/pythainlp/pythainlp/tag/_tag_perceptron.py,222
+pythainlp.tag.crfchunk.CRFchunk._model_file_ctx,tag,CRFchunk,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tag/crfchunk.py,90
+pythainlp.tag.crfchunk.CRFchunk._model_file_ctx,tag,CRFchunk,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tag/crfchunk.py,112
+pythainlp.tag.named_entity.NER.engine,tag,NER,public,/home/runner/work/pythainlp/pythainlp/pythainlp/tag/named_entity.py,51
+pythainlp.tag.named_entity.NER.engine,tag,NER,public,/home/runner/work/pythainlp/pythainlp/pythainlp/tag/named_entity.py,55
+pythainlp.tag.named_entity.NER.engine,tag,NER,public,/home/runner/work/pythainlp/pythainlp/pythainlp/tag/named_entity.py,61
+pythainlp.tag.named_entity.NER.engine,tag,NER,public,/home/runner/work/pythainlp/pythainlp/pythainlp/tag/named_entity.py,65
+pythainlp.tag.named_entity.NER.engine,tag,NER,public,/home/runner/work/pythainlp/pythainlp/pythainlp/tag/named_entity.py,73
+pythainlp.tag.named_entity.NER.engine,tag,NER,public,/home/runner/work/pythainlp/pythainlp/pythainlp/tag/named_entity.py,78
+pythainlp.tag.thainer.ThaiNameTagger.pos_tag_name,tag,ThaiNameTagger,public,/home/runner/work/pythainlp/pythainlp/pythainlp/tag/thainer.py,128
+pythainlp.tag.wangchanberta_onnx.WngchanBerta_ONNX._json,tag,WngchanBerta_ONNX,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tag/wangchanberta_onnx.py,55
+pythainlp.tag.wangchanberta_onnx.WngchanBerta_ONNX.id2tag,tag,WngchanBerta_ONNX,public,/home/runner/work/pythainlp/pythainlp/pythainlp/tag/wangchanberta_onnx.py,56
+pythainlp.tag.wangchanberta_onnx.WngchanBerta_ONNX._s,tag,WngchanBerta_ONNX,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tag/wangchanberta_onnx.py,101
+pythainlp.tokenize.attacut.AttacutTokenizer._MODEL_NAME,tokenize,AttacutTokenizer,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/attacut.py,23
+pythainlp.tokenize.attacut.AttacutTokenizer._MODEL_NAME,tokenize,AttacutTokenizer,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/attacut.py,26
+pythainlp.tokenize.attacut.AttacutTokenizer._tokenizer,tokenize,AttacutTokenizer,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/attacut.py,28
+pythainlp.tokenize.core.Tokenizer.__trie_dict,tokenize,Tokenizer,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/core.py,944
+pythainlp.tokenize.core.Tokenizer.__trie_dict,tokenize,Tokenizer,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/core.py,946
+pythainlp.tokenize.core.Tokenizer.__engine,tokenize,Tokenizer,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/core.py,996
+pythainlp.tokenize.han_solo.Featurizer.N,tokenize,Featurizer,public,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/han_solo.py,61
+pythainlp.tokenize.han_solo.Featurizer.delimiter,tokenize,Featurizer,public,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/han_solo.py,62
+pythainlp.tokenize.han_solo.Featurizer.radius,tokenize,Featurizer,public,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/han_solo.py,63
+pythainlp.tokenize.longest.LongestMatchTokenizer.__trie,tokenize,LongestMatchTokenizer,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/longest.py,52
+pythainlp.tokenize.multi_cut.LatticeString.unique,tokenize,LatticeString,public,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/multi_cut.py,45
+pythainlp.tokenize.multi_cut.LatticeString.multi,tokenize,LatticeString,public,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/multi_cut.py,47
+pythainlp.translate.core.Translate.model,translate,Translate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/core.py,75
+pythainlp.translate.core.Translate.model,translate,Translate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/core.py,79
+pythainlp.translate.core.Translate.model,translate,Translate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/core.py,83
+pythainlp.translate.core.Translate.model,translate,Translate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/core.py,87
+pythainlp.translate.core.Translate.model,translate,Translate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/core.py,91
+pythainlp.translate.core.Translate.model,translate,Translate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/core.py,95
+pythainlp.translate.en_th.EnThTranslator._model,translate,EnThTranslator,private,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/en_th.py,89
+pythainlp.translate.small100.Small100Translator.pretrained,translate,Small100Translator,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/small100.py,36
+pythainlp.translate.small100.Small100Translator.model,translate,Small100Translator,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/small100.py,37
+pythainlp.translate.small100.Small100Translator.tgt_lang,translate,Small100Translator,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/small100.py,40
+pythainlp.translate.small100.Small100Translator.model,translate,Small100Translator,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/small100.py,42
+pythainlp.translate.small100.Small100Translator.tokenizer,translate,Small100Translator,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/small100.py,74
+pythainlp.translate.small100.Small100Translator.tgt_lang,translate,Small100Translator,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/small100.py,77
+pythainlp.translate.small100.Small100Translator.translated,translate,Small100Translator,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/small100.py,78
+pythainlp.translate.th_fr.ThFrTranslator.tokenizer_thfr,translate,ThFrTranslator,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/th_fr.py,49
+pythainlp.translate.th_fr.ThFrTranslator.model_thfr,translate,ThFrTranslator,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/th_fr.py,50
+pythainlp.translate.th_fr.ThFrTranslator.model_thfr,translate,ThFrTranslator,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/th_fr.py,52
+pythainlp.translate.th_fr.ThFrTranslator.translated,translate,ThFrTranslator,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/th_fr.py,73
+pythainlp.translate.tokenization_small100.SMALL100Tokenizer.sp_model_kwargs,translate,SMALL100Tokenizer,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py,158
+pythainlp.translate.tokenization_small100.SMALL100Tokenizer.language_codes,translate,SMALL100Tokenizer,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py,162
+pythainlp.translate.tokenization_small100.SMALL100Tokenizer.lang_code_to_token,translate,SMALL100Tokenizer,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py,164
+pythainlp.translate.tokenization_small100.SMALL100Tokenizer.vocab_file,translate,SMALL100Tokenizer,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py,192
+pythainlp.translate.tokenization_small100.SMALL100Tokenizer.encoder,translate,SMALL100Tokenizer,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py,196
+pythainlp.translate.tokenization_small100.SMALL100Tokenizer.decoder,translate,SMALL100Tokenizer,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py,197
+pythainlp.translate.tokenization_small100.SMALL100Tokenizer.spm_file,translate,SMALL100Tokenizer,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py,198
+pythainlp.translate.tokenization_small100.SMALL100Tokenizer.sp_model,translate,SMALL100Tokenizer,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py,199
+pythainlp.translate.tokenization_small100.SMALL100Tokenizer.encoder_size,translate,SMALL100Tokenizer,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py,201
+pythainlp.translate.tokenization_small100.SMALL100Tokenizer.lang_token_to_id,translate,SMALL100Tokenizer,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py,203
+pythainlp.translate.tokenization_small100.SMALL100Tokenizer.lang_code_to_id,translate,SMALL100Tokenizer,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py,207
+pythainlp.translate.tokenization_small100.SMALL100Tokenizer.id_to_lang_token,translate,SMALL100Tokenizer,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py,211
+pythainlp.translate.tokenization_small100.SMALL100Tokenizer._tgt_lang,translate,SMALL100Tokenizer,private,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py,215
+pythainlp.translate.tokenization_small100.SMALL100Tokenizer.cur_lang_id,translate,SMALL100Tokenizer,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py,216
+pythainlp.translate.tokenization_small100.SMALL100Tokenizer.num_madeup_words,translate,SMALL100Tokenizer,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py,219
+pythainlp.translate.tokenization_small100.SMALL100Tokenizer._tgt_lang,translate,SMALL100Tokenizer,private,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py,232
+pythainlp.translate.tokenization_small100.SMALL100Tokenizer.__dict__,translate,SMALL100Tokenizer,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py,355
+pythainlp.translate.tokenization_small100.SMALL100Tokenizer.sp_model_kwargs,translate,SMALL100Tokenizer,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py,359
+pythainlp.translate.tokenization_small100.SMALL100Tokenizer.sp_model,translate,SMALL100Tokenizer,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py,361
+pythainlp.translate.tokenization_small100.SMALL100Tokenizer.tgt_lang,translate,SMALL100Tokenizer,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py,398
+pythainlp.translate.tokenization_small100.SMALL100Tokenizer.tgt_lang,translate,SMALL100Tokenizer,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py,411
+pythainlp.translate.tokenization_small100.SMALL100Tokenizer.prefix_tokens,translate,SMALL100Tokenizer,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py,419
+pythainlp.translate.tokenization_small100.SMALL100Tokenizer.suffix_tokens,translate,SMALL100Tokenizer,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py,420
+pythainlp.translate.tokenization_small100.SMALL100Tokenizer.cur_lang_id,translate,SMALL100Tokenizer,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py,426
+pythainlp.translate.tokenization_small100.SMALL100Tokenizer.prefix_tokens,translate,SMALL100Tokenizer,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py,427
+pythainlp.translate.tokenization_small100.SMALL100Tokenizer.suffix_tokens,translate,SMALL100Tokenizer,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py,428
+pythainlp.translate.zh_th.ThZhTranslator.tokenizer_thzh,translate,ThZhTranslator,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/zh_th.py,43
+pythainlp.translate.zh_th.ThZhTranslator.model_thzh,translate,ThZhTranslator,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/zh_th.py,44
+pythainlp.translate.zh_th.ThZhTranslator.model_thzh,translate,ThZhTranslator,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/zh_th.py,46
+pythainlp.translate.zh_th.ThZhTranslator.translated,translate,ThZhTranslator,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/zh_th.py,67
+pythainlp.translate.zh_th.ZhThTranslator.tokenizer_zhth,translate,ZhThTranslator,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/zh_th.py,99
+pythainlp.translate.zh_th.ZhThTranslator.model_zhth,translate,ZhThTranslator,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/zh_th.py,100
+pythainlp.translate.zh_th.ZhThTranslator.translated,translate,ZhThTranslator,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/zh_th.py,123
+pythainlp.transliterate.thai2rom.Encoder.hidden_size,transliterate,Encoder,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom.py,124
+pythainlp.transliterate.thai2rom.Encoder.character_embedding,transliterate,Encoder,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom.py,125
+pythainlp.transliterate.thai2rom.Encoder.rnn,transliterate,Encoder,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom.py,128
+pythainlp.transliterate.thai2rom.Encoder.dropout,transliterate,Encoder,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom.py,135
+pythainlp.transliterate.thai2rom.Attn.method,transliterate,Attn,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom.py,188
+pythainlp.transliterate.thai2rom.Attn.hidden_size,transliterate,Attn,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom.py,189
+pythainlp.transliterate.thai2rom.Attn.attn,transliterate,Attn,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom.py,194
+pythainlp.transliterate.thai2rom.Attn.attn,transliterate,Attn,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom.py,197
+pythainlp.transliterate.thai2rom.Attn.other,transliterate,Attn,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom.py,198
+pythainlp.transliterate.thai2rom.AttentionDecoder.vocabulary_size,transliterate,AttentionDecoder,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom.py,247
+pythainlp.transliterate.thai2rom.AttentionDecoder.hidden_size,transliterate,AttentionDecoder,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom.py,248
+pythainlp.transliterate.thai2rom.AttentionDecoder.character_embedding,transliterate,AttentionDecoder,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom.py,249
+pythainlp.transliterate.thai2rom.AttentionDecoder.rnn,transliterate,AttentionDecoder,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom.py,252
+pythainlp.transliterate.thai2rom.AttentionDecoder.attn,transliterate,AttentionDecoder,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom.py,259
+pythainlp.transliterate.thai2rom.AttentionDecoder.linear,transliterate,AttentionDecoder,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom.py,260
+pythainlp.transliterate.thai2rom.AttentionDecoder.dropout,transliterate,AttentionDecoder,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom.py,262
+pythainlp.transliterate.thai2rom.Seq2Seq.encoder,transliterate,Seq2Seq,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom.py,308
+pythainlp.transliterate.thai2rom.Seq2Seq.decoder,transliterate,Seq2Seq,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom.py,309
+pythainlp.transliterate.thai2rom.Seq2Seq.pad_idx,transliterate,Seq2Seq,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom.py,310
+pythainlp.transliterate.thai2rom.Seq2Seq.target_start_token,transliterate,Seq2Seq,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom.py,311
+pythainlp.transliterate.thai2rom.Seq2Seq.target_end_token,transliterate,Seq2Seq,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom.py,312
+pythainlp.transliterate.thai2rom.Seq2Seq.max_length,transliterate,Seq2Seq,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom.py,313
+pythainlp.transliterate.thai2rom_onnx.Seq2Seq_ONNX.encoder,transliterate,Seq2Seq_ONNX,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom_onnx.py,106
+pythainlp.transliterate.thai2rom_onnx.Seq2Seq_ONNX.decoder,transliterate,Seq2Seq_ONNX,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom_onnx.py,107
+pythainlp.transliterate.thai2rom_onnx.Seq2Seq_ONNX.pad_idx,transliterate,Seq2Seq_ONNX,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom_onnx.py,108
+pythainlp.transliterate.thai2rom_onnx.Seq2Seq_ONNX.target_start_token,transliterate,Seq2Seq_ONNX,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom_onnx.py,109
+pythainlp.transliterate.thai2rom_onnx.Seq2Seq_ONNX.target_end_token,transliterate,Seq2Seq_ONNX,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom_onnx.py,110
+pythainlp.transliterate.thai2rom_onnx.Seq2Seq_ONNX.max_length,transliterate,Seq2Seq_ONNX,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom_onnx.py,111
+pythainlp.transliterate.thai2rom_onnx.Seq2Seq_ONNX.target_vocab_size,transliterate,Seq2Seq_ONNX,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom_onnx.py,113
+pythainlp.transliterate.thaig2p.Encoder.hidden_size,transliterate,Encoder,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py,135
+pythainlp.transliterate.thaig2p.Encoder.character_embedding,transliterate,Encoder,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py,136
+pythainlp.transliterate.thaig2p.Encoder.rnn,transliterate,Encoder,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py,139
+pythainlp.transliterate.thaig2p.Encoder.dropout,transliterate,Encoder,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py,146
+pythainlp.transliterate.thaig2p.Attn.method,transliterate,Attn,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py,205
+pythainlp.transliterate.thaig2p.Attn.hidden_size,transliterate,Attn,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py,206
+pythainlp.transliterate.thaig2p.Attn.attn,transliterate,Attn,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py,212
+pythainlp.transliterate.thaig2p.AttentionDecoder.vocabulary_size,transliterate,AttentionDecoder,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py,264
+pythainlp.transliterate.thaig2p.AttentionDecoder.hidden_size,transliterate,AttentionDecoder,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py,265
+pythainlp.transliterate.thaig2p.AttentionDecoder.character_embedding,transliterate,AttentionDecoder,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py,266
+pythainlp.transliterate.thaig2p.AttentionDecoder.rnn,transliterate,AttentionDecoder,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py,269
+pythainlp.transliterate.thaig2p.AttentionDecoder.attn,transliterate,AttentionDecoder,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py,276
+pythainlp.transliterate.thaig2p.AttentionDecoder.linear,transliterate,AttentionDecoder,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py,277
+pythainlp.transliterate.thaig2p.AttentionDecoder.dropout,transliterate,AttentionDecoder,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py,279
+pythainlp.transliterate.thaig2p.Seq2Seq.encoder,transliterate,Seq2Seq,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py,325
+pythainlp.transliterate.thaig2p.Seq2Seq.decoder,transliterate,Seq2Seq,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py,326
+pythainlp.transliterate.thaig2p.Seq2Seq.pad_idx,transliterate,Seq2Seq,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py,327
+pythainlp.transliterate.thaig2p.Seq2Seq.target_start_token,transliterate,Seq2Seq,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py,328
+pythainlp.transliterate.thaig2p.Seq2Seq.target_end_token,transliterate,Seq2Seq,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py,329
+pythainlp.transliterate.thaig2p.Seq2Seq.max_length,transliterate,Seq2Seq,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py,330
+pythainlp.transliterate.umt5_thaig2p.Umt5ThaiG2P.pipe,transliterate,Umt5ThaiG2P,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/umt5_thaig2p.py,35
+pythainlp.transliterate.w2p.Thai_W2P.checkpoint,transliterate,Thai_W2P,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/w2p.py,89
+pythainlp.transliterate.w2p.Thai_W2P.word,transliterate,Thai_W2P,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/w2p.py,172
+pythainlp.transliterate.w2p.Thai_W2P.word,transliterate,Thai_W2P,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/w2p.py,173
+pythainlp.transliterate.wunsen.WunsenTransliterate.jp_input,transliterate,WunsenTransliterate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/wunsen.py,119
+pythainlp.transliterate.wunsen.WunsenTransliterate.zh_sandhi,transliterate,WunsenTransliterate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/wunsen.py,120
+pythainlp.transliterate.wunsen.WunsenTransliterate.system,transliterate,WunsenTransliterate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/wunsen.py,121
+pythainlp.transliterate.wunsen.WunsenTransliterate.jp_input,transliterate,WunsenTransliterate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/wunsen.py,123
+pythainlp.transliterate.wunsen.WunsenTransliterate.zh_sandhi,transliterate,WunsenTransliterate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/wunsen.py,124
+pythainlp.transliterate.wunsen.WunsenTransliterate.system,transliterate,WunsenTransliterate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/wunsen.py,125
+pythainlp.transliterate.wunsen.WunsenTransliterate.jp_input,transliterate,WunsenTransliterate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/wunsen.py,127
+pythainlp.transliterate.wunsen.WunsenTransliterate.zh_sandhi,transliterate,WunsenTransliterate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/wunsen.py,128
+pythainlp.transliterate.wunsen.WunsenTransliterate.system,transliterate,WunsenTransliterate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/wunsen.py,129
+pythainlp.transliterate.wunsen.WunsenTransliterate.lang,transliterate,WunsenTransliterate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/wunsen.py,134
+pythainlp.transliterate.wunsen.WunsenTransliterate.thap_value,transliterate,WunsenTransliterate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/wunsen.py,145
+pythainlp.util.trie.Trie.words,util,Trie,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/trie.py,60
+pythainlp.util.trie.Trie.root,util,Trie,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/trie.py,61
+pythainlp.wangchanberta.core.ThaiNameTagger.sent_ner,wangchanberta,ThaiNameTagger,public,/home/runner/work/pythainlp/pythainlp/pythainlp/wangchanberta/core.py,112
+pythainlp.wangchanberta.core.ThaiNameTagger.sent_ner,wangchanberta,ThaiNameTagger,public,/home/runner/work/pythainlp/pythainlp/pythainlp/wangchanberta/core.py,118
+pythainlp.wangchanberta.core.ThaiNameTagger.sent_ner,wangchanberta,ThaiNameTagger,public,/home/runner/work/pythainlp/pythainlp/pythainlp/wangchanberta/core.py,126
+pythainlp.word_vector.core.WordVector.tokenize,word_vector,WordVector,public,/home/runner/work/pythainlp/pythainlp/pythainlp/word_vector/core.py,68
+pythainlp.word_vector.core.WordVector.tokenize,word_vector,WordVector,public,/home/runner/work/pythainlp/pythainlp/pythainlp/word_vector/core.py,70
+pythainlp.wsd.core._SentenceTransformersModel.device,wsd,_SentenceTransformersModel,public,/home/runner/work/pythainlp/pythainlp/pythainlp/wsd/core.py,40
+pythainlp.wsd.core._SentenceTransformersModel.model,wsd,_SentenceTransformersModel,public,/home/runner/work/pythainlp/pythainlp/pythainlp/wsd/core.py,41
diff --git a/build_tools/analysis/output/module_variables_no_hints.csv b/build_tools/analysis/output/module_variables_no_hints.csv
new file mode 100644
index 000000000..53ae4af91
--- /dev/null
+++ b/build_tools/analysis/output/module_variables_no_hints.csv
@@ -0,0 +1,296 @@
+Variable Name,Submodule,Scope,File,Line
+pythainlp.ancient.aksonhan._dict_aksonhan,ancient,private,/home/runner/work/pythainlp/pythainlp/pythainlp/ancient/aksonhan.py,13
+pythainlp.ancient.aksonhan.unknown,ancient,public,/home/runner/work/pythainlp/pythainlp/pythainlp/ancient/aksonhan.py,18
+pythainlp.ancient.aksonhan.unknown,ancient,public,/home/runner/work/pythainlp/pythainlp/pythainlp/ancient/aksonhan.py,19
+pythainlp.ancient.aksonhan.unknown,ancient,public,/home/runner/work/pythainlp/pythainlp/pythainlp/ancient/aksonhan.py,20
+pythainlp.ancient.aksonhan._set_aksonhan,ancient,private,/home/runner/work/pythainlp/pythainlp/pythainlp/ancient/aksonhan.py,21
+pythainlp.ancient.aksonhan._trie,ancient,private,/home/runner/work/pythainlp/pythainlp/pythainlp/ancient/aksonhan.py,22
+pythainlp.ancient.aksonhan._tokenizer,ancient,private,/home/runner/work/pythainlp/pythainlp/pythainlp/ancient/aksonhan.py,23
+pythainlp.ancient.aksonhan._dict_thai,ancient,private,/home/runner/work/pythainlp/pythainlp/pythainlp/ancient/aksonhan.py,24
+pythainlp.augment.lm.phayathaibert._MODEL_NAME,augment,private,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/lm/phayathaibert.py,15
+pythainlp.augment.lm.wangchanberta.model_name,augment,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/lm/wangchanberta.py,11
+pythainlp.augment.word2vec.ltw2v.Word2VecAug,augment,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/word2vec/ltw2v.py,14
+pythainlp.augment.word2vec.thai2fit.Word2VecAug,augment,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/word2vec/thai2fit.py,14
+pythainlp.augment.wordnet.__all__,augment,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/wordnet.py,8
+pythainlp.augment.wordnet.orchid,augment,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/wordnet.py,23
+pythainlp.benchmarks.__all__,benchmarks,public,/home/runner/work/pythainlp/pythainlp/pythainlp/benchmarks/__init__.py,6
+pythainlp.benchmarks.word_tokenization.SEPARATOR,benchmarks,public,/home/runner/work/pythainlp/pythainlp/pythainlp/benchmarks/word_tokenization.py,13
+pythainlp.benchmarks.word_tokenization.SURROUNDING_SEPS_RX,benchmarks,public,/home/runner/work/pythainlp/pythainlp/pythainlp/benchmarks/word_tokenization.py,16
+pythainlp.benchmarks.word_tokenization.MULTIPLE_SEPS_RX,benchmarks,public,/home/runner/work/pythainlp/pythainlp/pythainlp/benchmarks/word_tokenization.py,21
+pythainlp.benchmarks.word_tokenization.TAG_RX,benchmarks,public,/home/runner/work/pythainlp/pythainlp/pythainlp/benchmarks/word_tokenization.py,24
+pythainlp.benchmarks.word_tokenization.TAILING_SEP_RX,benchmarks,public,/home/runner/work/pythainlp/pythainlp/pythainlp/benchmarks/word_tokenization.py,27
+pythainlp.cli.stdout,cli,public,/home/runner/work/pythainlp/pythainlp/pythainlp/cli/__init__.py,14
+pythainlp.cli.stderr,cli,public,/home/runner/work/pythainlp/pythainlp/pythainlp/cli/__init__.py,15
+pythainlp.cli.COMMANDS,cli,public,/home/runner/work/pythainlp/pythainlp/pythainlp/cli/__init__.py,18
+pythainlp.cli.CLI_NAME,cli,public,/home/runner/work/pythainlp/pythainlp/pythainlp/cli/__init__.py,22
+pythainlp.cli.COMMAND_MAP,cli,public,/home/runner/work/pythainlp/pythainlp/pythainlp/cli/__init__.py,47
+pythainlp.cli.command,cli,public,/home/runner/work/pythainlp/pythainlp/pythainlp/cli/__init__.py,58
+pythainlp.cli.tokenize.DEFAULT_SENT_TOKEN_SEPARATOR,cli,public,/home/runner/work/pythainlp/pythainlp/pythainlp/cli/tokenize.py,25
+pythainlp.cli.tokenize.DEFAULT_SUBWORD_TOKEN_SEPARATOR,cli,public,/home/runner/work/pythainlp/pythainlp/pythainlp/cli/tokenize.py,26
+pythainlp.cli.tokenize.DEFAULT_SYLLABLE_TOKEN_SEPARATOR,cli,public,/home/runner/work/pythainlp/pythainlp/pythainlp/cli/tokenize.py,27
+pythainlp.cli.tokenize.DEFAULT_WORD_TOKEN_SEPARATOR,cli,public,/home/runner/work/pythainlp/pythainlp/pythainlp/cli/tokenize.py,28
+pythainlp.coref.__all__,coref,public,/home/runner/work/pythainlp/pythainlp/pythainlp/coref/__init__.py,6
+pythainlp.coref.core._MODEL,coref,private,/home/runner/work/pythainlp/pythainlp/pythainlp/coref/core.py,8
+pythainlp.corpus.common.__all__,corpus,public,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py,15
+pythainlp.corpus.common._THAI_COUNTRIES_FILENAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py,37
+pythainlp.corpus.common._THAI_THAILAND_PROVINCES_FILENAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py,41
+pythainlp.corpus.common._THAI_SYLLABLES_FILENAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py,44
+pythainlp.corpus.common._THAI_WORDS_FILENAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py,47
+pythainlp.corpus.common._THAI_STOPWORDS_FILENAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py,50
+pythainlp.corpus.common._THAI_NEGATIONS_FILENAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py,53
+pythainlp.corpus.common._THAI_PROFANITY_WORDS_FILENAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py,56
+pythainlp.corpus.common._THAI_FAMLIY_NAMES_FILENAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py,59
+pythainlp.corpus.common._THAI_FEMALE_NAMES_FILENAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py,61
+pythainlp.corpus.common._THAI_MALE_NAMES_FILENAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py,63
+pythainlp.corpus.core._CHECK_MODE,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/core.py,25
+pythainlp.corpus.core._USER_AGENT,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/core.py,26
+pythainlp.corpus.icu._THAI_ICU_FILENAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/icu.py,10
+pythainlp.corpus.oscar.__all__,corpus,public,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/oscar.py,12
+pythainlp.corpus.oscar._OSCAR_FILENAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/oscar.py,18
+pythainlp.corpus.th_en_translit.__all__,corpus,public,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/th_en_translit.py,17
+pythainlp.corpus.th_en_translit._FILE_NAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/th_en_translit.py,23
+pythainlp.corpus.th_en_translit.TRANSLITERATE_EN,corpus,public,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/th_en_translit.py,24
+pythainlp.corpus.th_en_translit.TRANSLITERATE_FOLLOW_RTSG,corpus,public,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/th_en_translit.py,25
+pythainlp.corpus.th_en_translit.TRANSLITERATE_DICT,corpus,public,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/th_en_translit.py,80
+pythainlp.corpus.tnc.__all__,corpus,public,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/tnc.py,8
+pythainlp.corpus.tnc._UNIGRAM_FILENAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/tnc.py,19
+pythainlp.corpus.tnc._BIGRAM_CORPUS_NAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/tnc.py,20
+pythainlp.corpus.tnc._TRIGRAM_CORPUS_NAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/tnc.py,21
+pythainlp.corpus.ttc.__all__,corpus,public,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/ttc.py,12
+pythainlp.corpus.ttc._UNIGRAM_FILENAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/ttc.py,18
+pythainlp.corpus.volubilis._VOLUBILIS_WORDS,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/volubilis.py,10
+pythainlp.corpus.volubilis._VOLUBILIS_FILENAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/volubilis.py,11
+pythainlp.corpus.wikipedia._WIKIPEDIA_TITLES,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/wikipedia.py,10
+pythainlp.corpus.wikipedia._WIKIPEDIA_TITLES_FILENAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/wikipedia.py,11
+pythainlp.el.__all__,el,public,/home/runner/work/pythainlp/pythainlp/pythainlp/el/__init__.py,6
+pythainlp.generate.__all__,generate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/generate/__init__.py,6
+pythainlp.generate.thai2fit.__all__,generate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/generate/thai2fit.py,12
+pythainlp.generate.thai2fit.imdb,generate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/generate/thai2fit.py,41
+pythainlp.generate.thai2fit.dummy_df,generate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/generate/thai2fit.py,42
+pythainlp.generate.thai2fit.thwiki,generate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/generate/thai2fit.py,45
+pythainlp.generate.thai2fit.thwiki_itos,generate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/generate/thai2fit.py,61
+pythainlp.generate.thai2fit.thwiki_vocab,generate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/generate/thai2fit.py,62
+pythainlp.generate.thai2fit.tt,generate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/generate/thai2fit.py,65
+pythainlp.generate.thai2fit.processor,generate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/generate/thai2fit.py,71
+pythainlp.generate.thai2fit.data_lm,generate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/generate/thai2fit.py,75
+pythainlp.generate.thai2fit.config,generate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/generate/thai2fit.py,85
+pythainlp.generate.thai2fit.trn_args,generate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/generate/thai2fit.py,99
+pythainlp.generate.thai2fit.learn,generate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/generate/thai2fit.py,101
+pythainlp.lm.__all__,lm,public,/home/runner/work/pythainlp/pythainlp/pythainlp/lm/__init__.py,5
+pythainlp.morpheme.thaiwordcheck._TH_PREFIX_DIPHTHONG,morpheme,private,/home/runner/work/pythainlp/pythainlp/pythainlp/morpheme/thaiwordcheck.py,64
+pythainlp.morpheme.thaiwordcheck._TH_CONSONANTS_PATTERN,morpheme,private,/home/runner/work/pythainlp/pythainlp/pythainlp/morpheme/thaiwordcheck.py,68
+pythainlp.parse.core._tagger_name,parse,private,/home/runner/work/pythainlp/pythainlp/pythainlp/parse/core.py,9
+pythainlp.phayathaibert.__all__,phayathaibert,public,/home/runner/work/pythainlp/pythainlp/pythainlp/phayathaibert/__init__.py,6
+pythainlp.phayathaibert.core._PAT_URL,phayathaibert,private,/home/runner/work/pythainlp/pythainlp/pythainlp/phayathaibert/core.py,18
+pythainlp.phayathaibert.core._model_name,phayathaibert,private,/home/runner/work/pythainlp/pythainlp/pythainlp/phayathaibert/core.py,20
+pythainlp.phayathaibert.core._tokenizer,phayathaibert,private,/home/runner/work/pythainlp/pythainlp/pythainlp/phayathaibert/core.py,21
+pythainlp.soundex.complete_soundex._complete_soundex_instance,soundex,private,/home/runner/work/pythainlp/pythainlp/pythainlp/soundex/complete_soundex.py,616
+pythainlp.soundex.sound._ft,soundex,private,/home/runner/work/pythainlp/pythainlp/pythainlp/soundex/sound.py,12
+pythainlp.soundex.sound._dst,soundex,private,/home/runner/work/pythainlp/pythainlp/pythainlp/soundex/sound.py,13
+pythainlp.spell.phunspell.pspell,spell,public,/home/runner/work/pythainlp/pythainlp/pythainlp/spell/phunspell.py,22
+pythainlp.spell.symspellpy._UNIGRAM_FILENAME,spell,private,/home/runner/work/pythainlp/pythainlp/pythainlp/spell/symspellpy.py,28
+pythainlp.spell.symspellpy._BIGRAM_CORPUS_NAME,spell,private,/home/runner/work/pythainlp/pythainlp/pythainlp/spell/symspellpy.py,29
+pythainlp.spell.symspellpy._sym_spell,spell,private,/home/runner/work/pythainlp/pythainlp/pythainlp/spell/symspellpy.py,31
+pythainlp.spell.symspellpy._unigram_file_ctx,spell,private,/home/runner/work/pythainlp/pythainlp/pythainlp/spell/symspellpy.py,32
+pythainlp.spell.symspellpy._load_lock,spell,private,/home/runner/work/pythainlp/pythainlp/pythainlp/spell/symspellpy.py,35
+pythainlp.spell.wanchanberta_thai_grammarly.use_cuda,spell,public,/home/runner/work/pythainlp/pythainlp/pythainlp/spell/wanchanberta_thai_grammarly.py,27
+pythainlp.spell.wanchanberta_thai_grammarly.device,spell,public,/home/runner/work/pythainlp/pythainlp/pythainlp/spell/wanchanberta_thai_grammarly.py,28
+pythainlp.spell.wanchanberta_thai_grammarly.tokenizer,spell,public,/home/runner/work/pythainlp/pythainlp/pythainlp/spell/wanchanberta_thai_grammarly.py,29
+pythainlp.spell.wanchanberta_thai_grammarly.tagging_model,spell,public,/home/runner/work/pythainlp/pythainlp/pythainlp/spell/wanchanberta_thai_grammarly.py,56
+pythainlp.spell.wanchanberta_thai_grammarly.tagging_model,spell,public,/home/runner/work/pythainlp/pythainlp/pythainlp/spell/wanchanberta_thai_grammarly.py,58
+pythainlp.spell.wanchanberta_thai_grammarly.ids_to_labels,spell,public,/home/runner/work/pythainlp/pythainlp/pythainlp/spell/wanchanberta_thai_grammarly.py,59
+pythainlp.spell.wanchanberta_thai_grammarly.mlm_model,spell,public,/home/runner/work/pythainlp/pythainlp/pythainlp/spell/wanchanberta_thai_grammarly.py,100
+pythainlp.spell.wanchanberta_thai_grammarly.mlm_model,spell,public,/home/runner/work/pythainlp/pythainlp/pythainlp/spell/wanchanberta_thai_grammarly.py,104
+pythainlp.spell.words_spelling_correction._WSC,spell,private,/home/runner/work/pythainlp/pythainlp/pythainlp/spell/words_spelling_correction.py,271
+pythainlp.summarize.freq._STOPWORDS,summarize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/summarize/freq.py,16
+pythainlp.tag.thai_nner.__all__,tag,public,/home/runner/work/pythainlp/pythainlp/pythainlp/tag/thai_nner.py,18
+pythainlp.tag.thainer.__all__,tag,public,/home/runner/work/pythainlp/pythainlp/pythainlp/tag/thainer.py,8
+pythainlp.tag.thainer._TOKENIZER_ENGINE,tag,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tag/thainer.py,21
+pythainlp.tokenize._utils._DIGITS_WITH_SEPARATOR,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/_utils.py,11
+pythainlp.tokenize.attacut._tokenizers_lock,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/attacut.py,35
+pythainlp.tokenize.budoux._parser,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/budoux.py,18
+pythainlp.tokenize.budoux._parser_lock,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/budoux.py,19
+pythainlp.tokenize.core._RE_WHITESPACE,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/core.py,28
+pythainlp.tokenize.core._RE_WORD_CHAR,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/core.py,29
+pythainlp.tokenize.crfcut._ENDERS,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/crfcut.py,27
+pythainlp.tokenize.crfcut._STARTERS,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/crfcut.py,80
+pythainlp.tokenize.crfcut._CRFCUT_DATA_FILENAME,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/crfcut.py,177
+pythainlp.tokenize.crfcut._tagger,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/crfcut.py,178
+pythainlp.tokenize.etcc._PAT_ENDING_CHAR,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/etcc.py,37
+pythainlp.tokenize.etcc._RE_ENDING_CHAR,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/etcc.py,38
+pythainlp.tokenize.han_solo._tagger,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/han_solo.py,22
+pythainlp.tokenize.han_solo._model_file_ctx,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/han_solo.py,23
+pythainlp.tokenize.han_solo._load_lock,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/han_solo.py,24
+pythainlp.tokenize.han_solo._to_feature,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/han_solo.py,154
+pythainlp.tokenize.longest._FRONT_DEP_CHAR,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/longest.py,23
+pythainlp.tokenize.longest._REAR_DEP_CHAR,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/longest.py,39
+pythainlp.tokenize.longest._TRAILING_CHAR,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/longest.py,40
+pythainlp.tokenize.longest._RE_NONTHAI,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/longest.py,42
+pythainlp.tokenize.longest._KNOWN,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/longest.py,44
+pythainlp.tokenize.longest._UNKNOWN,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/longest.py,45
+pythainlp.tokenize.longest._tokenizers_lock,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/longest.py,163
+pythainlp.tokenize.multi_cut._RE_NONTHAI,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/multi_cut.py,51
+pythainlp.tokenize.multi_cut._PAT_NONTHAI,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/multi_cut.py,57
+pythainlp.tokenize.nercut._thainer,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/nercut.py,19
+pythainlp.tokenize.newmm._PAT_NONTHAI,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/newmm.py,32
+pythainlp.tokenize.newmm._PAT_THAI_TWOCHARS,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/newmm.py,43
+pythainlp.tokenize.newmm._MAX_GRAPH_SIZE,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/newmm.py,47
+pythainlp.tokenize.newmm._TEXT_SCAN_POINT,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/newmm.py,50
+pythainlp.tokenize.newmm._TEXT_SCAN_LEFT,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/newmm.py,51
+pythainlp.tokenize.newmm._TEXT_SCAN_RIGHT,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/newmm.py,52
+pythainlp.tokenize.newmm._TEXT_SCAN_BEGIN,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/newmm.py,53
+pythainlp.tokenize.newmm._TEXT_SCAN_END,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/newmm.py,54
+pythainlp.tokenize.nlpo3._NLPO3_DEFAULT_DICT_NAME,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/nlpo3.py,17
+pythainlp.tokenize.nlpo3._NLPO3_DEFAULT_DICT,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/nlpo3.py,18
+pythainlp.tokenize.nlpo3._dict_file_ctx,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/nlpo3.py,19
+pythainlp.tokenize.nlpo3._load_lock,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/nlpo3.py,20
+pythainlp.tokenize.oskut._DEFAULT_ENGINE,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/oskut.py,19
+pythainlp.tokenize.oskut._engine_lock,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/oskut.py,20
+pythainlp.tokenizeicu._thread_local,tokenizeicu,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/pyicu.py,21
+pythainlp.tokenize.sefr_cut._DEFAULT_ENGINE,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/sefr_cut.py,18
+pythainlp.tokenize.sefr_cut._engine_lock,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/sefr_cut.py,19
+pythainlp.tokenize.tcc._RE_TCC,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/tcc.py,20
+pythainlp.tokenize.tcc._PAT_TCC,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/tcc.py,59
+pythainlp.tokenize.tcc_p._RE_TCC,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/tcc_p.py,21
+pythainlp.tokenize.tcc_p._PAT_TCC,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/tcc_p.py,59
+pythainlp.tokenize.wtsplit._MODEL,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/wtsplit.py,16
+pythainlp.tokenize.wtsplit._MODEL_NAME,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/wtsplit.py,17
+pythainlp.tokenize.wtsplit._model_lock,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/wtsplit.py,18
+pythainlp.tools.misspell.THAI_CHARACTERS_WITHOUT_SHIFT,tools,public,/home/runner/work/pythainlp/pythainlp/pythainlp/tools/misspell.py,10
+pythainlp.tools.misspell.THAI_CHARACTERS_WITH_SHIFT,tools,public,/home/runner/work/pythainlp/pythainlp/pythainlp/tools/misspell.py,17
+pythainlp.tools.misspell.ENGLISH_CHARACTERS_WITHOUT_SHIFT,tools,public,/home/runner/work/pythainlp/pythainlp/pythainlp/tools/misspell.py,24
+pythainlp.tools.misspell.ENGLISH_CHARACTERS_WITH_SHIFT,tools,public,/home/runner/work/pythainlp/pythainlp/pythainlp/tools/misspell.py,31
+pythainlp.tools.misspell.ALL_CHARACTERS,tools,public,/home/runner/work/pythainlp/pythainlp/pythainlp/tools/misspell.py,39
+pythainlp.tools.path.PYTHAINLP_DEFAULT_DATA_DIR,tools,public,/home/runner/work/pythainlp/pythainlp/pythainlp/tools/path.py,21
+pythainlp.translate.__all__,translate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/__init__.py,6
+pythainlp.translate.en_th._EN_TH_MODEL_NAME,translate,private,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/en_th.py,32
+pythainlp.translate.en_th._EN_TH_FILE_NAME,translate,private,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/en_th.py,34
+pythainlp.translate.en_th._TH_EN_MODEL_NAME,translate,private,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/en_th.py,36
+pythainlp.translate.en_th._TH_EN_FILE_NAME,translate,private,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/en_th.py,38
+pythainlp.translate.tokenization_small100.SPIECE_UNDERLINE,translate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py,37
+pythainlp.translate.tokenization_small100.VOCAB_FILES_NAMES,translate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py,39
+pythainlp.translate.tokenization_small100.PRETRAINED_VOCAB_FILES_MAP,translate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py,45
+pythainlp.translate.tokenization_small100.PRETRAINED_POSITIONAL_EMBEDDINGS_SIZES,translate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py,57
+pythainlp.translate.tokenization_small100.FAIRSEQ_LANGUAGE_CODES,translate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py,62
+pythainlp.translate.word2word_translate.support_list,translate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/word2word_translate.py,10
+pythainlp.transliterate.iso_11940._all_dict,transliterate,private,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/iso_11940.py,125
+pythainlp.transliterate.iso_11940._keys_set,transliterate,private,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/iso_11940.py,131
+pythainlp.transliterate.lookup._TRANSLITERATE_IDX,transliterate,private,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/lookup.py,22
+pythainlp.transliterateicu._ICU_THAI_TO_LATIN,transliterateicu,private,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/pyicu.py,16
+pythainlp.transliterate.royin._vowel_patterns,transliterate,private,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/royin.py,73
+pythainlp.transliterate.royin._vowel_patterns,transliterate,private,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/royin.py,74
+pythainlp.transliterate.royin._vowel_patterns,transliterate,private,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/royin.py,75
+pythainlp.transliterate.spoonerism._list_consonants,transliterate,private,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/spoonerism.py,9
+pythainlp.transliterate.thai2rom.device,transliterate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom.py,20
+pythainlp.transliterate.thai2rom._MODEL_NAME,transliterate,private,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom.py,22
+pythainlp.transliterate.thai2rom._THAI_TO_ROM,transliterate,private,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom.py,398
+pythainlp.transliterate.thai2rom_onnx._MODEL_ENCODER_NAME,transliterate,private,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom_onnx.py,19
+pythainlp.transliterate.thai2rom_onnx._MODEL_DECODER_NAME,transliterate,private,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom_onnx.py,20
+pythainlp.transliterate.thai2rom_onnx._MODEL_CONFIG_NAME,transliterate,private,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom_onnx.py,21
+pythainlp.transliterate.thai2rom_onnx._THAI_TO_ROM_ONNX,transliterate,private,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom_onnx.py,184
+pythainlp.transliterate.thaig2p.device,transliterate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py,23
+pythainlp.transliterate.thaig2p._MODEL_NAME,transliterate,private,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py,25
+pythainlp.transliterate.thaig2p._THAI_G2P,transliterate,private,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py,413
+pythainlp.transliterate.thaig2p_v2._THAI_G2P,transliterate,private,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p_v2.py,45
+pythainlp.transliterate.umt5_thaig2p._THAI_G2P,transliterate,private,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/umt5_thaig2p.py,45
+pythainlp.transliterate.w2p._GRAPHEMES,transliterate,private,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/w2p.py,19
+pythainlp.transliterate.w2p._PHONEMES,transliterate,private,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/w2p.py,22
+pythainlp.transliterate.w2p._MODEL_NAME,transliterate,private,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/w2p.py,26
+pythainlp.transliterate.w2p.hp,transliterate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/w2p.py,41
+pythainlp.transliterate.w2p._THAI_W2P,transliterate,private,/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/w2p.py,229
+pythainlp.ulmfit.core.device,ulmfit,public,/home/runner/work/pythainlp/pythainlp/pythainlp/ulmfit/core.py,34
+pythainlp.ulmfit.core._MODEL_NAME_LSTM,ulmfit,private,/home/runner/work/pythainlp/pythainlp/pythainlp/ulmfit/core.py,36
+pythainlp.ulmfit.core._ITOS_NAME_LSTM,ulmfit,private,/home/runner/work/pythainlp/pythainlp/pythainlp/ulmfit/core.py,37
+pythainlp.ulmfit.core.THWIKI_LSTM,ulmfit,public,/home/runner/work/pythainlp/pythainlp/pythainlp/ulmfit/core.py,44
+pythainlp.ulmfit.core.pre_rules_th,ulmfit,public,/home/runner/work/pythainlp/pythainlp/pythainlp/ulmfit/core.py,76
+pythainlp.ulmfit.core.post_rules_th,ulmfit,public,/home/runner/work/pythainlp/pythainlp/pythainlp/ulmfit/core.py,86
+pythainlp.ulmfit.core.pre_rules_th_sparse,ulmfit,public,/home/runner/work/pythainlp/pythainlp/pythainlp/ulmfit/core.py,89
+pythainlp.ulmfit.core.post_rules_th_sparse,ulmfit,public,/home/runner/work/pythainlp/pythainlp/pythainlp/ulmfit/core.py,90
+pythainlp.ulmfit.preprocess._TK_UNK,ulmfit,private,/home/runner/work/pythainlp/pythainlp/pythainlp/ulmfit/preprocess.py,15
+pythainlp.ulmfit.preprocess._TK_REP,ulmfit,private,/home/runner/work/pythainlp/pythainlp/pythainlp/ulmfit/preprocess.py,16
+pythainlp.ulmfit.preprocess._TK_WREP,ulmfit,private,/home/runner/work/pythainlp/pythainlp/pythainlp/ulmfit/preprocess.py,17
+pythainlp.ulmfit.preprocess._TK_END,ulmfit,private,/home/runner/work/pythainlp/pythainlp/pythainlp/ulmfit/preprocess.py,18
+pythainlp.ulmfit.preprocess._TK_URL,ulmfit,private,/home/runner/work/pythainlp/pythainlp/pythainlp/ulmfit/preprocess.py,19
+pythainlp.util.collate._RE_TONE,util,private,/home/runner/work/pythainlp/pythainlp/pythainlp/util/collate.py,13
+pythainlp.util.collate._RE_LV_C,util,private,/home/runner/work/pythainlp/pythainlp/pythainlp/util/collate.py,14
+pythainlp.util.date.__all__,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/date.py,17
+pythainlp.util.date.thai_abbr_weekdays,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/date.py,31
+pythainlp.util.date.thai_full_weekdays,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/date.py,32
+pythainlp.util.date.thai_abbr_months,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/date.py,42
+pythainlp.util.date.thai_full_months,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/date.py,56
+pythainlp.util.date.thai_full_month_lists,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/date.py,70
+pythainlp.util.date.thai_full_month_lists_regex,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/date.py,84
+pythainlp.util.date.year_all_regex,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/date.py,87
+pythainlp.util.date.dates_list,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/date.py,88
+pythainlp.util.date._DAY,util,private,/home/runner/work/pythainlp/pythainlp/pythainlp/util/date.py,96
+pythainlp.util.digitconv._spell_digit,util,private,/home/runner/work/pythainlp/pythainlp/pythainlp/util/digitconv.py,47
+pythainlp.util.digitconv._arabic_thai_translate_table,util,private,/home/runner/work/pythainlp/pythainlp/pythainlp/util/digitconv.py,60
+pythainlp.util.digitconv._thai_arabic_translate_table,util,private,/home/runner/work/pythainlp/pythainlp/pythainlp/util/digitconv.py,61
+pythainlp.util.digitconv._digit_spell_translate_table,util,private,/home/runner/work/pythainlp/pythainlp/pythainlp/util/digitconv.py,62
+pythainlp.util.emojiconv._th_emoji,util,private,/home/runner/work/pythainlp/pythainlp/pythainlp/util/emojiconv.py,1829
+pythainlp.util.emojiconv._emojis,util,private,/home/runner/work/pythainlp/pythainlp/pythainlp/util/emojiconv.py,1831
+pythainlp.util.emojiconv._emoji_regex,util,private,/home/runner/work/pythainlp/pythainlp/pythainlp/util/emojiconv.py,1832
+pythainlp.util.emojiconv._delimiter,util,private,/home/runner/work/pythainlp/pythainlp/pythainlp/util/emojiconv.py,1833
+pythainlp.util.keyboard.EN_TH_KEYB_PAIRS,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/keyboard.py,10
+pythainlp.util.keyboard.TH_EN_KEYB_PAIRS,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/keyboard.py,105
+pythainlp.util.keyboard.EN_TH_TRANSLATE_TABLE,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/keyboard.py,107
+pythainlp.util.keyboard.TH_EN_TRANSLATE_TABLE,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/keyboard.py,108
+pythainlp.util.keyboard.TIS_820_2531_MOD,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/keyboard.py,110
+pythainlp.util.keyboard.TIS_820_2531_MOD_SHIFT,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/keyboard.py,116
+pythainlp.util.keywords._STOPWORDS,util,private,/home/runner/work/pythainlp/pythainlp/pythainlp/util/keywords.py,11
+pythainlp.util.morse.unknown,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/morse.py,126
+pythainlp.util.morse.unknown,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/morse.py,130
+pythainlp.util.morse.unknown,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/morse.py,133
+pythainlp.util.normalize._RE_TONEMARKS,util,private,/home/runner/work/pythainlp/pythainlp/pythainlp/util/normalize.py,51
+pythainlp.util.normalize._RE_REMOVE_NEWLINES,util,private,/home/runner/work/pythainlp/pythainlp/pythainlp/util/normalize.py,53
+pythainlp.util.normalize._RE_REMOVE_SPACES_BEFORE_NONBASE,util,private,/home/runner/work/pythainlp/pythainlp/pythainlp/util/normalize.py,58
+pythainlp.util.phoneme.consonants_ipa_nectec,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/phoneme.py,14
+pythainlp.util.phoneme.monophthong_ipa_nectec,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/phoneme.py,39
+pythainlp.util.phoneme.diphthong_ipa_nectec,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/phoneme.py,62
+pythainlp.util.phoneme.tones_ipa_nectec,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/phoneme.py,71
+pythainlp.util.phoneme.dict_nectec_to_ipa,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/phoneme.py,79
+pythainlp.util.phoneme.dict_ipa_rtgs,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/phoneme.py,124
+pythainlp.util.phoneme.dict_ipa_rtgs_final,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/phoneme.py,194
+pythainlp.util.pronounce.kv,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/pronounce.py,14
+pythainlp.util.pronounce.all_thai_words_dict,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/pronounce.py,15
+pythainlp.util.pronounce.thai_vowel,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/pronounce.py,45
+pythainlp.util.pronounce.thai_vowel_all,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/pronounce.py,51
+pythainlp.util.spell_words._r1,util,private,/home/runner/work/pythainlp/pythainlp/pythainlp/util/spell_words.py,21
+pythainlp.util.spell_words._r2,util,private,/home/runner/work/pythainlp/pythainlp/pythainlp/util/spell_words.py,22
+pythainlp.util.spell_words.tonemarks,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/spell_words.py,23
+pythainlp.util.spell_words.dict_vowel_ex,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/spell_words.py,38
+pythainlp.util.spell_words.unknown,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/spell_words.py,40
+pythainlp.util.spell_words.dict_vowel,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/spell_words.py,43
+pythainlp.util.spell_words.unknown,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/spell_words.py,45
+pythainlp.util.spell_words.unknown,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/spell_words.py,49
+pythainlp.util.spell_words.unknown,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/spell_words.py,51
+pythainlp.util.spell_words.unknown,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/spell_words.py,53
+pythainlp.util.spell_words.unknown,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/spell_words.py,55
+pythainlp.util.strftime.__all__,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/strftime.py,20
+pythainlp.util.strftime._HA_TH_DIGITS,util,private,/home/runner/work/pythainlp/pythainlp/pythainlp/util/strftime.py,24
+pythainlp.util.strftime._BE_AD_DIFFERENCE,util,private,/home/runner/work/pythainlp/pythainlp/pythainlp/util/strftime.py,25
+pythainlp.util.strftime._NEED_L10N,util,private,/home/runner/work/pythainlp/pythainlp/pythainlp/util/strftime.py,27
+pythainlp.util.strftime._EXTENSIONS,util,private,/home/runner/work/pythainlp/pythainlp/pythainlp/util/strftime.py,28
+pythainlp.util.syllable.unknown,util,public,/home/runner/work/pythainlp/pythainlp/pythainlp/util/syllable.py,61
+pythainlp.util.thai_lunar_date._BEGIN_DATES,util,private,/home/runner/work/pythainlp/pythainlp/pythainlp/util/thai_lunar_date.py,129
+pythainlp.util.thai_lunar_date._DAYS_354,util,private,/home/runner/work/pythainlp/pythainlp/pythainlp/util/thai_lunar_date.py,188
+pythainlp.util.thai_lunar_date._DAYS_355,util,private,/home/runner/work/pythainlp/pythainlp/pythainlp/util/thai_lunar_date.py,189
+pythainlp.util.thai_lunar_date._DAYS_384,util,private,/home/runner/work/pythainlp/pythainlp/pythainlp/util/thai_lunar_date.py,190
+pythainlp.util.time._TIME_FORMAT_WITH_SEC,util,private,/home/runner/work/pythainlp/pythainlp/pythainlp/util/time.py,19
+pythainlp.util.time._TIME_FORMAT_WITHOUT_SEC,util,private,/home/runner/work/pythainlp/pythainlp/pythainlp/util/time.py,20
+pythainlp.util.time._DICT_THAI_TIME,util,private,/home/runner/work/pythainlp/pythainlp/pythainlp/util/time.py,21
+pythainlp.util.time._THAI_TIME_AFFIX,util,private,/home/runner/work/pythainlp/pythainlp/pythainlp/util/time.py,56
+pythainlp.wangchanberta.__all__,wangchanberta,public,/home/runner/work/pythainlp/pythainlp/pythainlp/wangchanberta/__init__.py,4
+pythainlp.wangchanberta.core._model_name,wangchanberta,private,/home/runner/work/pythainlp/pythainlp/pythainlp/wangchanberta/core.py,16
+pythainlp.wangchanberta.core._tokenizer,wangchanberta,private,/home/runner/work/pythainlp/pythainlp/pythainlp/wangchanberta/core.py,17
+pythainlp.word_vector.core.WV_DIM,word_vector,public,/home/runner/work/pythainlp/pythainlp/pythainlp/word_vector/core.py,15
+pythainlp.word_vector.core._MODEL_NAME,word_vector,private,/home/runner/work/pythainlp/pythainlp/pythainlp/word_vector/core.py,17
+pythainlp.word_vector.core._TK_SP,word_vector,private,/home/runner/work/pythainlp/pythainlp/pythainlp/word_vector/core.py,19
+pythainlp.word_vector.core._TK_EOL,word_vector,private,/home/runner/work/pythainlp/pythainlp/pythainlp/word_vector/core.py,20
+pythainlp.wsd.core._wsd_dict,wsd,private,/home/runner/work/pythainlp/pythainlp/pythainlp/wsd/core.py,12
+pythainlp.wsd.core._mean_all,wsd,private,/home/runner/work/pythainlp/pythainlp/pythainlp/wsd/core.py,13
+pythainlp.wsd.core.unknown,wsd,public,/home/runner/work/pythainlp/pythainlp/pythainlp/wsd/core.py,16
+pythainlp.wsd.core._all_word,wsd,private,/home/runner/work/pythainlp/pythainlp/pythainlp/wsd/core.py,18
+pythainlp.wsd.core._TRIE,wsd,private,/home/runner/work/pythainlp/pythainlp/pythainlp/wsd/core.py,19
+pythainlp.wsd.core._word_cut,wsd,private,/home/runner/work/pythainlp/pythainlp/pythainlp/wsd/core.py,20
+pythainlp.wsd.core._MODEL,wsd,private,/home/runner/work/pythainlp/pythainlp/pythainlp/wsd/core.py,22
diff --git a/build_tools/analysis/output/submodule_summary.csv b/build_tools/analysis/output/submodule_summary.csv
index c56f26f31..06e7dace0 100644
--- a/build_tools/analysis/output/submodule_summary.csv
+++ b/build_tools/analysis/output/submodule_summary.csv
@@ -1,32 +1,32 @@
Submodule,Total,Complete,Incomplete,None,% Complete,Mypy Errors
__main__,1,1,0,0,100.00%,0
-ancient,2,2,0,0,100.00%,1
-augment,29,29,0,0,100.00%,1
-benchmarks,8,8,0,0,100.00%,1
-chat,4,4,0,0,100.00%,1
-classify,5,5,0,0,100.00%,1
-cli,21,21,0,0,100.00%,1
-coref,5,5,0,0,100.00%,1
-corpus,70,70,0,0,100.00%,1
-el,5,5,0,0,100.00%,1
-generate,15,15,0,0,100.00%,1
-khavee,9,9,0,0,100.00%,1
-lm,2,2,0,0,100.00%,1
-morpheme,2,2,0,0,100.00%,1
-parse,9,9,0,0,100.00%,1
-phayathaibert,19,19,0,0,100.00%,1
-soundex,27,27,0,0,100.00%,1
-spell,43,43,0,0,100.00%,1
-summarize,17,17,0,0,100.00%,1
-tag,68,68,0,0,100.00%,1
-tokenize,73,73,0,0,100.00%,1
+ancient,2,2,0,0,100.00%,0
+augment,29,29,0,0,100.00%,0
+benchmarks,8,8,0,0,100.00%,0
+chat,4,4,0,0,100.00%,0
+classify,5,5,0,0,100.00%,0
+cli,21,21,0,0,100.00%,0
+coref,5,5,0,0,100.00%,0
+corpus,70,70,0,0,100.00%,0
+el,5,5,0,0,100.00%,0
+generate,15,15,0,0,100.00%,0
+khavee,9,9,0,0,100.00%,0
+lm,2,2,0,0,100.00%,0
+morpheme,2,2,0,0,100.00%,0
+parse,9,9,0,0,100.00%,0
+phayathaibert,19,19,0,0,100.00%,0
+soundex,27,27,0,0,100.00%,0
+spell,43,43,0,0,100.00%,0
+summarize,17,17,0,0,100.00%,0
+tag,73,73,0,0,100.00%,0
+tokenize,73,73,0,0,100.00%,0
tokenizeicu,3,3,0,0,100.00%,0
-tools,9,9,0,0,100.00%,1
-translate,44,44,0,0,100.00%,1
-transliterate,75,75,0,0,100.00%,1
+tools,9,9,0,0,100.00%,0
+translate,44,44,0,0,100.00%,0
+transliterate,75,75,0,0,100.00%,0
transliterateicu,1,1,0,0,100.00%,0
-ulmfit,25,25,0,0,100.00%,1
-util,109,109,0,0,100.00%,1
-wangchanberta,9,9,0,0,100.00%,1
-word_vector,7,7,0,0,100.00%,1
-wsd,4,4,0,0,100.00%,1
+ulmfit,25,25,0,0,100.00%,0
+util,109,109,0,0,100.00%,0
+wangchanberta,9,9,0,0,100.00%,0
+word_vector,7,7,0,0,100.00%,0
+wsd,4,4,0,0,100.00%,0
diff --git a/build_tools/analysis/output/type_aliases.csv b/build_tools/analysis/output/type_aliases.csv
new file mode 100644
index 000000000..ce7759191
--- /dev/null
+++ b/build_tools/analysis/output/type_aliases.csv
@@ -0,0 +1 @@
+Type Alias Name,Submodule,Scope,File,Line
diff --git a/build_tools/analysis/output/type_hint_analysis.json b/build_tools/analysis/output/type_hint_analysis.json
index 1a65f2521..9029ff919 100644
--- a/build_tools/analysis/output/type_hint_analysis.json
+++ b/build_tools/analysis/output/type_hint_analysis.json
@@ -10,13 +10,13 @@
"pct_none": 0.0
},
"variables": {
- "total": 1158,
- "complete": 655,
- "none": 503,
- "pct_complete": 56.56303972366149,
- "pct_none": 43.43696027633852,
- "class_variables": 205,
- "instance_variables": 442,
+ "total": 1166,
+ "complete": 661,
+ "none": 505,
+ "pct_complete": 56.68953687821612,
+ "pct_none": 43.310463121783876,
+ "class_variables": 216,
+ "instance_variables": 439,
"module_variables": 511
},
"type_aliases": {
@@ -231,14 +231,14 @@
"scope": "public",
"parent_class": "FastTextAug",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/augment/lm/fasttext.py",
- "line": 31
+ "line": 35
},
{
"name": "pythainlp.augment.lm.fasttext.FastTextAug.model",
"scope": "public",
"parent_class": "FastTextAug",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/augment/lm/fasttext.py",
- "line": 33
+ "line": 37
},
{
"name": "pythainlp.augment.lm.phayathaibert.ThaiTextAugmenter.tokenizer",
@@ -574,49 +574,63 @@
"scope": "public",
"parent_class": "FastTextEncoder",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/words_spelling_correction.py",
- "line": 57
+ "line": 68
},
{
"name": "pythainlp.spell.words_spelling_correction.FastTextEncoder.nn_model_path",
"scope": "public",
"parent_class": "FastTextEncoder",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/words_spelling_correction.py",
- "line": 58
+ "line": 69
},
{
"name": "pythainlp.spell.words_spelling_correction.FastTextEncoder.bucket",
"scope": "public",
"parent_class": "FastTextEncoder",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/words_spelling_correction.py",
- "line": 59
+ "line": 70
},
{
"name": "pythainlp.spell.words_spelling_correction.FastTextEncoder.nb_words",
"scope": "public",
"parent_class": "FastTextEncoder",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/words_spelling_correction.py",
- "line": 60
+ "line": 71
},
{
"name": "pythainlp.spell.words_spelling_correction.FastTextEncoder.minn",
"scope": "public",
"parent_class": "FastTextEncoder",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/words_spelling_correction.py",
- "line": 61
+ "line": 72
},
{
"name": "pythainlp.spell.words_spelling_correction.FastTextEncoder.maxn",
"scope": "public",
"parent_class": "FastTextEncoder",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/words_spelling_correction.py",
- "line": 62
+ "line": 73
+ },
+ {
+ "name": "pythainlp.spell.words_spelling_correction.FastTextEncoder.words_for_suggestion",
+ "scope": "public",
+ "parent_class": "FastTextEncoder",
+ "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/words_spelling_correction.py",
+ "line": 77
+ },
+ {
+ "name": "pythainlp.spell.words_spelling_correction.FastTextEncoder.nn_session",
+ "scope": "public",
+ "parent_class": "FastTextEncoder",
+ "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/words_spelling_correction.py",
+ "line": 78
},
{
"name": "pythainlp.spell.words_spelling_correction.Words_Spelling_Correction.list_word",
"scope": "public",
"parent_class": "Words_Spelling_Correction",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/words_spelling_correction.py",
- "line": 247
+ "line": 267
},
{
"name": "pythainlp.summarize.keybert.KeyBERT.ft_pipeline",
@@ -938,182 +952,182 @@
"scope": "public",
"parent_class": "SMALL100Tokenizer",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py",
- "line": 156
+ "line": 158
},
{
"name": "pythainlp.translate.tokenization_small100.SMALL100Tokenizer.language_codes",
"scope": "public",
"parent_class": "SMALL100Tokenizer",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py",
- "line": 160
+ "line": 162
},
{
"name": "pythainlp.translate.tokenization_small100.SMALL100Tokenizer.lang_code_to_token",
"scope": "public",
"parent_class": "SMALL100Tokenizer",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py",
- "line": 162
+ "line": 164
},
{
"name": "pythainlp.translate.tokenization_small100.SMALL100Tokenizer.vocab_file",
"scope": "public",
"parent_class": "SMALL100Tokenizer",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py",
- "line": 190
+ "line": 192
},
{
"name": "pythainlp.translate.tokenization_small100.SMALL100Tokenizer.encoder",
"scope": "public",
"parent_class": "SMALL100Tokenizer",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py",
- "line": 194
+ "line": 196
},
{
"name": "pythainlp.translate.tokenization_small100.SMALL100Tokenizer.decoder",
"scope": "public",
"parent_class": "SMALL100Tokenizer",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py",
- "line": 195
+ "line": 197
},
{
"name": "pythainlp.translate.tokenization_small100.SMALL100Tokenizer.spm_file",
"scope": "public",
"parent_class": "SMALL100Tokenizer",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py",
- "line": 196
+ "line": 198
},
{
"name": "pythainlp.translate.tokenization_small100.SMALL100Tokenizer.sp_model",
"scope": "public",
"parent_class": "SMALL100Tokenizer",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py",
- "line": 197
+ "line": 199
},
{
"name": "pythainlp.translate.tokenization_small100.SMALL100Tokenizer.encoder_size",
"scope": "public",
"parent_class": "SMALL100Tokenizer",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py",
- "line": 199
+ "line": 201
},
{
"name": "pythainlp.translate.tokenization_small100.SMALL100Tokenizer.lang_token_to_id",
"scope": "public",
"parent_class": "SMALL100Tokenizer",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py",
- "line": 201
+ "line": 203
},
{
"name": "pythainlp.translate.tokenization_small100.SMALL100Tokenizer.lang_code_to_id",
"scope": "public",
"parent_class": "SMALL100Tokenizer",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py",
- "line": 205
+ "line": 207
},
{
"name": "pythainlp.translate.tokenization_small100.SMALL100Tokenizer.id_to_lang_token",
"scope": "public",
"parent_class": "SMALL100Tokenizer",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py",
- "line": 209
+ "line": 211
},
{
"name": "pythainlp.translate.tokenization_small100.SMALL100Tokenizer._tgt_lang",
"scope": "private",
"parent_class": "SMALL100Tokenizer",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py",
- "line": 213
+ "line": 215
},
{
"name": "pythainlp.translate.tokenization_small100.SMALL100Tokenizer.cur_lang_id",
"scope": "public",
"parent_class": "SMALL100Tokenizer",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py",
- "line": 214
+ "line": 216
},
{
"name": "pythainlp.translate.tokenization_small100.SMALL100Tokenizer.num_madeup_words",
"scope": "public",
"parent_class": "SMALL100Tokenizer",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py",
- "line": 217
+ "line": 219
},
{
"name": "pythainlp.translate.tokenization_small100.SMALL100Tokenizer._tgt_lang",
"scope": "private",
"parent_class": "SMALL100Tokenizer",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py",
- "line": 230
+ "line": 232
},
{
"name": "pythainlp.translate.tokenization_small100.SMALL100Tokenizer.__dict__",
"scope": "public",
"parent_class": "SMALL100Tokenizer",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py",
- "line": 353
+ "line": 355
},
{
"name": "pythainlp.translate.tokenization_small100.SMALL100Tokenizer.sp_model_kwargs",
"scope": "public",
"parent_class": "SMALL100Tokenizer",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py",
- "line": 357
+ "line": 359
},
{
"name": "pythainlp.translate.tokenization_small100.SMALL100Tokenizer.sp_model",
"scope": "public",
"parent_class": "SMALL100Tokenizer",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py",
- "line": 359
+ "line": 361
},
{
"name": "pythainlp.translate.tokenization_small100.SMALL100Tokenizer.tgt_lang",
"scope": "public",
"parent_class": "SMALL100Tokenizer",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py",
- "line": 396
+ "line": 398
},
{
"name": "pythainlp.translate.tokenization_small100.SMALL100Tokenizer.tgt_lang",
"scope": "public",
"parent_class": "SMALL100Tokenizer",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py",
- "line": 409
+ "line": 411
},
{
"name": "pythainlp.translate.tokenization_small100.SMALL100Tokenizer.prefix_tokens",
"scope": "public",
"parent_class": "SMALL100Tokenizer",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py",
- "line": 417
+ "line": 419
},
{
"name": "pythainlp.translate.tokenization_small100.SMALL100Tokenizer.suffix_tokens",
"scope": "public",
"parent_class": "SMALL100Tokenizer",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py",
- "line": 418
+ "line": 420
},
{
"name": "pythainlp.translate.tokenization_small100.SMALL100Tokenizer.cur_lang_id",
"scope": "public",
"parent_class": "SMALL100Tokenizer",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py",
- "line": 424
+ "line": 426
},
{
"name": "pythainlp.translate.tokenization_small100.SMALL100Tokenizer.prefix_tokens",
"scope": "public",
"parent_class": "SMALL100Tokenizer",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py",
- "line": 425
+ "line": 427
},
{
"name": "pythainlp.translate.tokenization_small100.SMALL100Tokenizer.suffix_tokens",
"scope": "public",
"parent_class": "SMALL100Tokenizer",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py",
- "line": 426
+ "line": 428
},
{
"name": "pythainlp.translate.zh_th.ThZhTranslator.tokenizer_thzh",
@@ -1631,21 +1645,21 @@
"scope": "public",
"parent_class": "ThaiNameTagger",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/wangchanberta/core.py",
- "line": 108
+ "line": 112
},
{
"name": "pythainlp.wangchanberta.core.ThaiNameTagger.sent_ner",
"scope": "public",
"parent_class": "ThaiNameTagger",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/wangchanberta/core.py",
- "line": 114
+ "line": 118
},
{
"name": "pythainlp.wangchanberta.core.ThaiNameTagger.sent_ner",
"scope": "public",
"parent_class": "ThaiNameTagger",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/wangchanberta/core.py",
- "line": 122
+ "line": 126
},
{
"name": "pythainlp.word_vector.core.WordVector.tokenize",
@@ -2293,7 +2307,7 @@
"name": "pythainlp.spell.words_spelling_correction._WSC",
"scope": "private",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/words_spelling_correction.py",
- "line": 251
+ "line": 271
},
{
"name": "pythainlp.summarize.freq._STOPWORDS",
@@ -2689,31 +2703,31 @@
"name": "pythainlp.translate.tokenization_small100.SPIECE_UNDERLINE",
"scope": "public",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py",
- "line": 35
+ "line": 37
},
{
"name": "pythainlp.translate.tokenization_small100.VOCAB_FILES_NAMES",
"scope": "public",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py",
- "line": 37
+ "line": 39
},
{
"name": "pythainlp.translate.tokenization_small100.PRETRAINED_VOCAB_FILES_MAP",
"scope": "public",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py",
- "line": 43
+ "line": 45
},
{
"name": "pythainlp.translate.tokenization_small100.PRETRAINED_POSITIONAL_EMBEDDINGS_SIZES",
"scope": "public",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py",
- "line": 55
+ "line": 57
},
{
"name": "pythainlp.translate.tokenization_small100.FAIRSEQ_LANGUAGE_CODES",
"scope": "public",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/translate/tokenization_small100.py",
- "line": 60
+ "line": 62
},
{
"name": "pythainlp.translate.word2word_translate.support_list",
@@ -3373,13 +3387,13 @@
"name": "pythainlp.wangchanberta.core._model_name",
"scope": "private",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/wangchanberta/core.py",
- "line": 12
+ "line": 16
},
{
"name": "pythainlp.wangchanberta.core._tokenizer",
"scope": "private",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/wangchanberta/core.py",
- "line": 13
+ "line": 17
},
{
"name": "pythainlp.word_vector.core.WV_DIM",
From ebc942edb82022d02068b8315f5d0aec34367b3d Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 4 Feb 2026 08:13:32 +0000
Subject: [PATCH 03/17] Add type hints to module-level variables in multiple
modules
Added type annotations to module-level variables in:
- ancient/aksonhan.py
- augment/wordnet.py, lm/phayathaibert.py, lm/wangchanberta.py, word2vec/ltw2v.py, word2vec/thai2fit.py
- benchmarks/__init__.py, word_tokenization.py
- cli/__init__.py, tokenize.py
- corpus/common.py, core.py, icu.py, oscar.py
- coref/__init__.py
Co-authored-by: bact <128572+bact@users.noreply.github.com>
---
pythainlp/ancient/aksonhan.py | 10 +++++-----
pythainlp/augment/lm/fasttext.py | 8 ++++++--
pythainlp/augment/lm/phayathaibert.py | 4 ++--
pythainlp/augment/lm/wangchanberta.py | 4 ++--
pythainlp/augment/word2vec/bpemb_wv.py | 2 +-
pythainlp/augment/word2vec/core.py | 6 ++++--
pythainlp/augment/word2vec/ltw2v.py | 2 +-
pythainlp/augment/word2vec/thai2fit.py | 2 +-
pythainlp/augment/wordnet.py | 12 ++++++++----
pythainlp/benchmarks/__init__.py | 2 +-
pythainlp/benchmarks/word_tokenization.py | 10 +++++-----
pythainlp/cli/__init__.py | 16 ++++++++++------
pythainlp/cli/tokenize.py | 8 ++++----
pythainlp/coref/__init__.py | 2 +-
pythainlp/coref/_fastcoref.py | 4 +++-
pythainlp/coref/han_coref.py | 4 +++-
pythainlp/corpus/common.py | 22 +++++++++++-----------
pythainlp/corpus/core.py | 7 ++++---
pythainlp/corpus/icu.py | 2 +-
pythainlp/corpus/oscar.py | 4 ++--
20 files changed, 75 insertions(+), 56 deletions(-)
diff --git a/pythainlp/ancient/aksonhan.py b/pythainlp/ancient/aksonhan.py
index 88a0a843b..7649ea616 100644
--- a/pythainlp/ancient/aksonhan.py
+++ b/pythainlp/ancient/aksonhan.py
@@ -10,7 +10,7 @@
from pythainlp.tokenize import Tokenizer
from pythainlp.util import Trie
-_dict_aksonhan = {}
+_dict_aksonhan: dict[str, str] = {}
for i in list(thai_consonants):
if i == "ร":
continue
@@ -18,10 +18,10 @@
_dict_aksonhan[i + j + i] = "ั" + j + i
_dict_aksonhan[i + i + j + i] = i + "ั" + j + i
_dict_aksonhan[i + i] = "ั" + i
-_set_aksonhan = set(_dict_aksonhan.keys())
-_trie = Trie(chain(_dict_aksonhan.keys(), thai_consonants))
-_tokenizer = Tokenizer(custom_dict=_trie, engine="mm")
-_dict_thai = set(thai_orst_words()) # call Thai words
+_set_aksonhan: set[str] = set(_dict_aksonhan.keys())
+_trie: Trie = Trie(chain(_dict_aksonhan.keys(), thai_consonants))
+_tokenizer: Tokenizer = Tokenizer(custom_dict=_trie, engine="mm")
+_dict_thai: set[str] = set(thai_orst_words()) # call Thai words
def aksonhan_to_current(word: str) -> str:
diff --git a/pythainlp/augment/lm/fasttext.py b/pythainlp/augment/lm/fasttext.py
index 6c5dad320..0c8188c7f 100644
--- a/pythainlp/augment/lm/fasttext.py
+++ b/pythainlp/augment/lm/fasttext.py
@@ -30,7 +30,9 @@ def __init__(self, model_path: str) -> None:
from gensim.models.keyedvectors import KeyedVectors
if model_path.endswith(".bin"):
- self.model: Union[FastText, KeyedVectors] = FastText_gensim.load_facebook_vectors(model_path)
+ self.model: Union[FastText, KeyedVectors] = (
+ FastText_gensim.load_facebook_vectors(model_path)
+ )
elif model_path.endswith(".vec"):
self.model = KeyedVectors.load_word2vec_format(model_path)
else:
@@ -80,7 +82,9 @@ def augment(
:rtype: List[Tuple[str]]
"""
self.sentence: list[str] = self.tokenize(sentence)
- self.list_synonym: list[list[str]] = self.modify_sent(self.sentence, p=p)
+ self.list_synonym: list[list[str]] = self.modify_sent(
+ self.sentence, p=p
+ )
new_sentences = []
for x in list(itertools.product(*self.list_synonym))[0:n_sent]:
new_sentences.append(x)
diff --git a/pythainlp/augment/lm/phayathaibert.py b/pythainlp/augment/lm/phayathaibert.py
index eada2f975..8aa4b0316 100644
--- a/pythainlp/augment/lm/phayathaibert.py
+++ b/pythainlp/augment/lm/phayathaibert.py
@@ -5,14 +5,14 @@
import random
import re
-from typing import TYPE_CHECKING, Any
+from typing import TYPE_CHECKING
if TYPE_CHECKING:
from transformers import AutoModelForMaskedLM, AutoTokenizer, Pipeline
from pythainlp.phayathaibert.core import ThaiTextProcessor
-_MODEL_NAME = "clicknext/phayathaibert"
+_MODEL_NAME: str = "clicknext/phayathaibert"
class ThaiTextAugmenter:
diff --git a/pythainlp/augment/lm/wangchanberta.py b/pythainlp/augment/lm/wangchanberta.py
index 49ee6ecd2..8ca1e0202 100644
--- a/pythainlp/augment/lm/wangchanberta.py
+++ b/pythainlp/augment/lm/wangchanberta.py
@@ -3,12 +3,12 @@
# SPDX-License-Identifier: Apache-2.0
from __future__ import annotations
-from typing import TYPE_CHECKING, Any
+from typing import TYPE_CHECKING
if TYPE_CHECKING:
from transformers import CamembertTokenizer, Pipeline
-model_name = "airesearch/wangchanberta-base-att-spm-uncased"
+model_name: str = "airesearch/wangchanberta-base-att-spm-uncased"
class Thai2transformersAug:
diff --git a/pythainlp/augment/word2vec/bpemb_wv.py b/pythainlp/augment/word2vec/bpemb_wv.py
index 5e43bbdee..50a743372 100644
--- a/pythainlp/augment/word2vec/bpemb_wv.py
+++ b/pythainlp/augment/word2vec/bpemb_wv.py
@@ -3,7 +3,7 @@
# SPDX-License-Identifier: Apache-2.0
from __future__ import annotations
-from typing import TYPE_CHECKING, Any
+from typing import TYPE_CHECKING
from pythainlp.augment.word2vec.core import Word2VecAug
diff --git a/pythainlp/augment/word2vec/core.py b/pythainlp/augment/word2vec/core.py
index 2a177625b..849e2790b 100644
--- a/pythainlp/augment/word2vec/core.py
+++ b/pythainlp/augment/word2vec/core.py
@@ -4,7 +4,7 @@
from __future__ import annotations
import itertools
-from typing import TYPE_CHECKING, Any, Callable
+from typing import TYPE_CHECKING, Callable
if TYPE_CHECKING:
from gensim.models.keyedvectors import KeyedVectors
@@ -29,7 +29,9 @@ def __init__(
self.tokenizer: Callable[[str], list[str]] = tokenize
if type == "file":
- self.model: "KeyedVectors" = word2vec.KeyedVectors.load_word2vec_format(model)
+ self.model: "KeyedVectors" = (
+ word2vec.KeyedVectors.load_word2vec_format(model)
+ )
elif type == "binary":
self.model = word2vec.KeyedVectors.load_word2vec_format(
model, binary=True, unicode_errors="ignore"
diff --git a/pythainlp/augment/word2vec/ltw2v.py b/pythainlp/augment/word2vec/ltw2v.py
index 8f7d8ebe8..bfa12a140 100644
--- a/pythainlp/augment/word2vec/ltw2v.py
+++ b/pythainlp/augment/word2vec/ltw2v.py
@@ -11,7 +11,7 @@
from pythainlp.augment.word2vec.core import Word2VecAug as _Word2VecAug
# Make it accessible for runtime
-Word2VecAug = _Word2VecAug
+Word2VecAug: type[_Word2VecAug] = _Word2VecAug
from pythainlp.corpus import get_corpus_path
from pythainlp.tokenize import word_tokenize
diff --git a/pythainlp/augment/word2vec/thai2fit.py b/pythainlp/augment/word2vec/thai2fit.py
index 18c54b706..9c4ef0821 100644
--- a/pythainlp/augment/word2vec/thai2fit.py
+++ b/pythainlp/augment/word2vec/thai2fit.py
@@ -11,7 +11,7 @@
from pythainlp.augment.word2vec.core import Word2VecAug as _Word2VecAug
# Make it accessible for runtime
-Word2VecAug = _Word2VecAug
+Word2VecAug: type[_Word2VecAug] = _Word2VecAug
from pythainlp.corpus import get_corpus_path
from pythainlp.tokenize import thai2fit_tokenizer
diff --git a/pythainlp/augment/wordnet.py b/pythainlp/augment/wordnet.py
index 740d3566f..19219ea83 100644
--- a/pythainlp/augment/wordnet.py
+++ b/pythainlp/augment/wordnet.py
@@ -5,7 +5,7 @@
from __future__ import annotations
-__all__ = [
+__all__: list[str] = [
"WordNetAug",
"postype2wordnet",
]
@@ -20,7 +20,7 @@
from pythainlp.tag import pos_tag
from pythainlp.tokenize import word_tokenize
-orchid = {
+orchid: dict[str, str] = {
"": "",
# NOUN
"NOUN": wn.NOUN,
@@ -192,9 +192,13 @@ def augment(
self.list_synonym: list[list[str]] = []
self.p_all: int = 1
if postag:
- self.list_pos: list[tuple[str, str]] = pos_tag(self.list_words, corpus=postag_corpus)
+ self.list_pos: list[tuple[str, str]] = pos_tag(
+ self.list_words, corpus=postag_corpus
+ )
for word, pos in self.list_pos:
- self.temp: list[str] = self.find_synonyms(word, pos, postag_corpus)
+ self.temp: list[str] = self.find_synonyms(
+ word, pos, postag_corpus
+ )
if not self.temp:
self.list_synonym.append([word])
else:
diff --git a/pythainlp/benchmarks/__init__.py b/pythainlp/benchmarks/__init__.py
index 954076a96..497c0cf6a 100644
--- a/pythainlp/benchmarks/__init__.py
+++ b/pythainlp/benchmarks/__init__.py
@@ -3,6 +3,6 @@
# SPDX-License-Identifier: Apache-2.0
"""Performance benchmarking."""
-__all__ = ["benchmark"]
+__all__: list[str] = ["benchmark"]
from pythainlp.benchmarks.word_tokenization import benchmark
diff --git a/pythainlp/benchmarks/word_tokenization.py b/pythainlp/benchmarks/word_tokenization.py
index 3cd874641..8a58e6360 100644
--- a/pythainlp/benchmarks/word_tokenization.py
+++ b/pythainlp/benchmarks/word_tokenization.py
@@ -10,21 +10,21 @@
import numpy as np
import pandas as pd
-SEPARATOR = "|"
+SEPARATOR: str = "|"
# regex for removing one space surrounded by separators, i.e. | |
-SURROUNDING_SEPS_RX = re.compile(
+SURROUNDING_SEPS_RX: re.Pattern[str] = re.compile(
"{sep}? ?{sep}$".format(sep=re.escape(SEPARATOR))
)
# regex for removing repeated separators, i.e. ||||
-MULTIPLE_SEPS_RX = re.compile(f"{re.escape(SEPARATOR)}+")
+MULTIPLE_SEPS_RX: re.Pattern[str] = re.compile(f"{re.escape(SEPARATOR)}+")
# regex for removing tags, i.e. ,
-TAG_RX = re.compile(r"<\/?[A-Z]+>")
+TAG_RX: re.Pattern[str] = re.compile(r"<\/?[A-Z]+>")
# regex for removing trailing separators, i.e. a|dog| -> a|dog
-TAILING_SEP_RX = re.compile(f"{re.escape(SEPARATOR)}$")
+TAILING_SEP_RX: re.Pattern[str] = re.compile(f"{re.escape(SEPARATOR)}$")
def _f1(precision: float, recall: float) -> float:
diff --git a/pythainlp/cli/__init__.py b/pythainlp/cli/__init__.py
index 50c50be6d..d3c4666b7 100644
--- a/pythainlp/cli/__init__.py
+++ b/pythainlp/cli/__init__.py
@@ -8,18 +8,22 @@
import io
import sys
from argparse import ArgumentError, ArgumentParser
+from typing import TYPE_CHECKING
from pythainlp.cli import benchmark, data, misspell, soundex, tag, tokenize
-sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")
-sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8")
+if TYPE_CHECKING:
+ from types import ModuleType
+
+sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8") # type: ignore[assignment]
+sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8") # type: ignore[assignment]
# a command should start with a verb when possible
-COMMANDS = sorted(
+COMMANDS: list[str] = sorted(
["data", "soundex", "tag", "tokenize", "benchmark", "misspell"]
)
-CLI_NAME = "thainlp"
+CLI_NAME: str = "thainlp"
def make_usage(command: str) -> dict[str, str]:
@@ -44,7 +48,7 @@ def exit_if_empty(command: str, parser: ArgumentParser) -> None:
if __name__ == "__main__":
# Create a simple mapping from command name to the imported module
- COMMAND_MAP = {
+ COMMAND_MAP: dict[str, ModuleType] = {
"tokenize": tokenize,
"soundex": soundex,
"tag": tag,
@@ -55,7 +59,7 @@ def exit_if_empty(command: str, parser: ArgumentParser) -> None:
# Check if a command was provided and if it's one we know
if len(sys.argv) > 1 and sys.argv[1] in COMMAND_MAP:
- command = sys.argv[1]
+ command: str = sys.argv[1]
COMMAND_MAP[command].run()
else:
if len(sys.argv) < 2:
diff --git a/pythainlp/cli/tokenize.py b/pythainlp/cli/tokenize.py
index efbc9cbea..7c66c8269 100644
--- a/pythainlp/cli/tokenize.py
+++ b/pythainlp/cli/tokenize.py
@@ -22,10 +22,10 @@
if TYPE_CHECKING:
from collections.abc import Callable, Sequence
-DEFAULT_SENT_TOKEN_SEPARATOR = "@@" # noqa: S105
-DEFAULT_SUBWORD_TOKEN_SEPARATOR = "/" # noqa: S105
-DEFAULT_SYLLABLE_TOKEN_SEPARATOR = "~" # noqa: S105
-DEFAULT_WORD_TOKEN_SEPARATOR = "|" # noqa: S105
+DEFAULT_SENT_TOKEN_SEPARATOR: str = "@@" # noqa: S105
+DEFAULT_SUBWORD_TOKEN_SEPARATOR: str = "/" # noqa: S105
+DEFAULT_SYLLABLE_TOKEN_SEPARATOR: str = "~" # noqa: S105
+DEFAULT_WORD_TOKEN_SEPARATOR: str = "|" # noqa: S105
class SubAppBase:
diff --git a/pythainlp/coref/__init__.py b/pythainlp/coref/__init__.py
index cc985376e..883bc970c 100644
--- a/pythainlp/coref/__init__.py
+++ b/pythainlp/coref/__init__.py
@@ -3,6 +3,6 @@
# SPDX-License-Identifier: Apache-2.0
"""PyThaiNLP Coreference Resolution"""
-__all__ = ["coreference_resolution"]
+__all__: list[str] = ["coreference_resolution"]
from pythainlp.coref.core import coreference_resolution
diff --git a/pythainlp/coref/_fastcoref.py b/pythainlp/coref/_fastcoref.py
index b43f2f019..79c041ac5 100644
--- a/pythainlp/coref/_fastcoref.py
+++ b/pythainlp/coref/_fastcoref.py
@@ -30,7 +30,9 @@ def __init__(
self.model_name: str = model_name
self.nlp: Language = nlp
- self.model: CorefModel = _model(self.model_name, device=device, nlp=self.nlp)
+ self.model: CorefModel = _model(
+ self.model_name, device=device, nlp=self.nlp
+ )
def _to_json(self, _predict: Any) -> dict[str, Any]:
return {
diff --git a/pythainlp/coref/han_coref.py b/pythainlp/coref/han_coref.py
index bd7c2d743..6d2b0e94f 100644
--- a/pythainlp/coref/han_coref.py
+++ b/pythainlp/coref/han_coref.py
@@ -12,7 +12,9 @@
class HanCoref(FastCoref):
- def __init__(self, device: str = "cpu", nlp: Optional[Language] = None) -> None:
+ def __init__(
+ self, device: str = "cpu", nlp: Optional[Language] = None
+ ) -> None:
super().__init__(
model_name="pythainlp/han-coref-v1.0", device=device, nlp=nlp
)
diff --git a/pythainlp/corpus/common.py b/pythainlp/corpus/common.py
index e56a2b4b8..7acc36e27 100644
--- a/pythainlp/corpus/common.py
+++ b/pythainlp/corpus/common.py
@@ -12,7 +12,7 @@
if TYPE_CHECKING:
from typing import Any, Union
-__all__ = [
+__all__: list[str] = [
"countries",
"find_synonyms",
"provinces",
@@ -34,33 +34,33 @@
from pythainlp.tools import warn_deprecation
_THAI_COUNTRIES: frozenset[str] = frozenset()
-_THAI_COUNTRIES_FILENAME = "countries_th.txt"
+_THAI_COUNTRIES_FILENAME: str = "countries_th.txt"
_THAI_THAILAND_PROVINCES: frozenset[str] = frozenset()
_THAI_THAILAND_PROVINCES_DETAILS: list[dict[str, str]] = []
-_THAI_THAILAND_PROVINCES_FILENAME = "thailand_provinces_th.csv"
+_THAI_THAILAND_PROVINCES_FILENAME: str = "thailand_provinces_th.csv"
_THAI_SYLLABLES: frozenset[str] = frozenset()
-_THAI_SYLLABLES_FILENAME = "syllables_th.txt"
+_THAI_SYLLABLES_FILENAME: str = "syllables_th.txt"
_THAI_WORDS: frozenset[str] = frozenset()
-_THAI_WORDS_FILENAME = "words_th.txt"
+_THAI_WORDS_FILENAME: str = "words_th.txt"
_THAI_STOPWORDS: frozenset[str] = frozenset()
-_THAI_STOPWORDS_FILENAME = "stopwords_th.txt"
+_THAI_STOPWORDS_FILENAME: str = "stopwords_th.txt"
_THAI_NEGATIONS: frozenset[str] = frozenset()
-_THAI_NEGATIONS_FILENAME = "negations_th.txt"
+_THAI_NEGATIONS_FILENAME: str = "negations_th.txt"
_THAI_PROFANITY_WORDS: frozenset[str] = frozenset()
-_THAI_PROFANITY_WORDS_FILENAME = "profanity_th.txt"
+_THAI_PROFANITY_WORDS_FILENAME: str = "profanity_th.txt"
_THAI_FAMLIY_NAMES: frozenset[str] = frozenset()
-_THAI_FAMLIY_NAMES_FILENAME = "family_names_th.txt"
+_THAI_FAMLIY_NAMES_FILENAME: str = "family_names_th.txt"
_THAI_FEMALE_NAMES: frozenset[str] = frozenset()
-_THAI_FEMALE_NAMES_FILENAME = "person_names_female_th.txt"
+_THAI_FEMALE_NAMES_FILENAME: str = "person_names_female_th.txt"
_THAI_MALE_NAMES: frozenset[str] = frozenset()
-_THAI_MALE_NAMES_FILENAME = "person_names_male_th.txt"
+_THAI_MALE_NAMES_FILENAME: str = "person_names_male_th.txt"
_THAI_ORST_WORDS: frozenset[str] = frozenset()
diff --git a/pythainlp/corpus/core.py b/pythainlp/corpus/core.py
index ad6bf539b..614bb32b8 100644
--- a/pythainlp/corpus/core.py
+++ b/pythainlp/corpus/core.py
@@ -5,6 +5,7 @@
from __future__ import annotations
+import http.client
import json
import os
import re
@@ -22,8 +23,8 @@
if TYPE_CHECKING:
from typing import Any, Optional
-_CHECK_MODE = os.getenv("PYTHAINLP_READ_MODE")
-_USER_AGENT = (
+_CHECK_MODE: str | None = os.getenv("PYTHAINLP_READ_MODE")
+_USER_AGENT: str = (
f"PyThaiNLP/{__version__} "
f"(Python/{sys.version_info.major}.{sys.version_info.minor}; "
f"{sys.platform})"
@@ -34,7 +35,7 @@ class _ResponseWrapper:
"""Wrapper to provide requests.Response-like interface for urllib response."""
status_code: int
- headers: "http.client.HTTPMessage"
+ headers: http.client.HTTPMessage
_content: bytes
def __init__(self, response: HTTPResponse) -> None:
diff --git a/pythainlp/corpus/icu.py b/pythainlp/corpus/icu.py
index 5a0d54c50..20e519f72 100644
--- a/pythainlp/corpus/icu.py
+++ b/pythainlp/corpus/icu.py
@@ -7,7 +7,7 @@
from pythainlp.corpus.core import get_corpus
-_THAI_ICU_FILENAME = "icubrk_th.txt"
+_THAI_ICU_FILENAME: str = "icubrk_th.txt"
def thai_icu_words() -> frozenset[str]:
diff --git a/pythainlp/corpus/oscar.py b/pythainlp/corpus/oscar.py
index 8475119ba..a435afa45 100644
--- a/pythainlp/corpus/oscar.py
+++ b/pythainlp/corpus/oscar.py
@@ -9,13 +9,13 @@
from __future__ import annotations
-__all__ = ["word_freqs", "unigram_word_freqs"]
+__all__: list[str] = ["word_freqs", "unigram_word_freqs"]
from collections import defaultdict
from pythainlp.corpus import get_corpus_path
-_OSCAR_FILENAME = "oscar_icu"
+_OSCAR_FILENAME: str = "oscar_icu"
def word_freqs() -> list[tuple[str, int]]:
From b9f73daa85829a4d5a417056229709894ffca977 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 4 Feb 2026 08:16:08 +0000
Subject: [PATCH 04/17] Add type hints to more module-level variables
Added type annotations to module-level variables in:
- corpus/th_en_translit.py
- tools/misspell.py, path.py
- morpheme/thaiwordcheck.py
- word_vector/core.py
- wsd/core.py
- soundex/sound.py, complete_soundex.py
Progress: Variables type coverage improved from 56.69% to 62.52% (729/1166)
Co-authored-by: bact <128572+bact@users.noreply.github.com>
---
.../analysis/output/type_hint_analysis.json | 496 ++----------------
pythainlp/corpus/th_en_translit.py | 12 +-
pythainlp/morpheme/thaiwordcheck.py | 5 +-
pythainlp/soundex/complete_soundex.py | 6 +-
pythainlp/soundex/sound.py | 4 +-
pythainlp/soundex/udom83.py | 8 +-
pythainlp/tools/misspell.py | 10 +-
pythainlp/tools/path.py | 2 +-
pythainlp/word_vector/core.py | 8 +-
pythainlp/wsd/core.py | 21 +-
10 files changed, 88 insertions(+), 484 deletions(-)
diff --git a/build_tools/analysis/output/type_hint_analysis.json b/build_tools/analysis/output/type_hint_analysis.json
index 9029ff919..fb82d0cc0 100644
--- a/build_tools/analysis/output/type_hint_analysis.json
+++ b/build_tools/analysis/output/type_hint_analysis.json
@@ -11,10 +11,10 @@
},
"variables": {
"total": 1166,
- "complete": 661,
- "none": 505,
- "pct_complete": 56.68953687821612,
- "pct_none": 43.310463121783876,
+ "complete": 729,
+ "none": 437,
+ "pct_complete": 62.52144082332761,
+ "pct_none": 37.478559176672384,
"class_variables": 216,
"instance_variables": 439,
"module_variables": 511
@@ -37,121 +37,121 @@
"complete": 2,
"incomplete": 0,
"none": 0,
- "mypy_errors": 0
+ "mypy_errors": 26
},
"augment": {
"complete": 29,
"incomplete": 0,
"none": 0,
- "mypy_errors": 0
+ "mypy_errors": 33
},
"benchmarks": {
"complete": 8,
"incomplete": 0,
"none": 0,
- "mypy_errors": 0
+ "mypy_errors": 26
},
"chat": {
"complete": 4,
"incomplete": 0,
"none": 0,
- "mypy_errors": 0
+ "mypy_errors": 28
},
"classify": {
"complete": 5,
"incomplete": 0,
"none": 0,
- "mypy_errors": 0
+ "mypy_errors": 26
},
"cli": {
"complete": 21,
"incomplete": 0,
"none": 0,
- "mypy_errors": 0
+ "mypy_errors": 28
},
"coref": {
"complete": 5,
"incomplete": 0,
"none": 0,
- "mypy_errors": 0
+ "mypy_errors": 26
},
"corpus": {
"complete": 70,
"incomplete": 0,
"none": 0,
- "mypy_errors": 0
+ "mypy_errors": 26
},
"el": {
"complete": 5,
"incomplete": 0,
"none": 0,
- "mypy_errors": 0
+ "mypy_errors": 26
},
"generate": {
"complete": 15,
"incomplete": 0,
"none": 0,
- "mypy_errors": 0
+ "mypy_errors": 31
},
"khavee": {
"complete": 9,
"incomplete": 0,
"none": 0,
- "mypy_errors": 0
+ "mypy_errors": 26
},
"lm": {
"complete": 2,
"incomplete": 0,
"none": 0,
- "mypy_errors": 0
+ "mypy_errors": 26
},
"morpheme": {
"complete": 2,
"incomplete": 0,
"none": 0,
- "mypy_errors": 0
+ "mypy_errors": 26
},
"parse": {
"complete": 9,
"incomplete": 0,
"none": 0,
- "mypy_errors": 0
+ "mypy_errors": 28
},
"phayathaibert": {
"complete": 19,
"incomplete": 0,
"none": 0,
- "mypy_errors": 0
+ "mypy_errors": 26
},
"soundex": {
"complete": 27,
"incomplete": 0,
"none": 0,
- "mypy_errors": 0
+ "mypy_errors": 26
},
"spell": {
"complete": 43,
"incomplete": 0,
"none": 0,
- "mypy_errors": 0
+ "mypy_errors": 26
},
"summarize": {
"complete": 17,
"incomplete": 0,
"none": 0,
- "mypy_errors": 0
+ "mypy_errors": 31
},
"tag": {
"complete": 73,
"incomplete": 0,
"none": 0,
- "mypy_errors": 0
+ "mypy_errors": 28
},
"tokenize": {
"complete": 73,
"incomplete": 0,
"none": 0,
- "mypy_errors": 0
+ "mypy_errors": 26
},
"tokenizeicu": {
"complete": 3,
@@ -163,19 +163,19 @@
"complete": 9,
"incomplete": 0,
"none": 0,
- "mypy_errors": 0
+ "mypy_errors": 26
},
"translate": {
"complete": 44,
"incomplete": 0,
"none": 0,
- "mypy_errors": 0
+ "mypy_errors": 33
},
"transliterate": {
"complete": 75,
"incomplete": 0,
"none": 0,
- "mypy_errors": 0
+ "mypy_errors": 27
},
"transliterateicu": {
"complete": 1,
@@ -187,31 +187,31 @@
"complete": 25,
"incomplete": 0,
"none": 0,
- "mypy_errors": 0
+ "mypy_errors": 30
},
"util": {
"complete": 109,
"incomplete": 0,
"none": 0,
- "mypy_errors": 0
+ "mypy_errors": 26
},
"wangchanberta": {
"complete": 9,
"incomplete": 0,
"none": 0,
- "mypy_errors": 0
+ "mypy_errors": 26
},
"word_vector": {
"complete": 7,
"incomplete": 0,
"none": 0,
- "mypy_errors": 0
+ "mypy_errors": 33
},
"wsd": {
"complete": 4,
"incomplete": 0,
"none": 0,
- "mypy_errors": 0
+ "mypy_errors": 28
}
},
"functions_no_hints": [],
@@ -231,14 +231,14 @@
"scope": "public",
"parent_class": "FastTextAug",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/augment/lm/fasttext.py",
- "line": 35
+ "line": 37
},
{
"name": "pythainlp.augment.lm.fasttext.FastTextAug.model",
"scope": "public",
"parent_class": "FastTextAug",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/augment/lm/fasttext.py",
- "line": 37
+ "line": 39
},
{
"name": "pythainlp.augment.lm.phayathaibert.ThaiTextAugmenter.tokenizer",
@@ -364,14 +364,14 @@
"scope": "public",
"parent_class": "Word2VecAug",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/augment/word2vec/core.py",
- "line": 34
+ "line": 36
},
{
"name": "pythainlp.augment.word2vec.core.Word2VecAug.model",
"scope": "public",
"parent_class": "Word2VecAug",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/augment/word2vec/core.py",
- "line": 38
+ "line": 40
},
{
"name": "pythainlp.augment.word2vec.ltw2v.LTW2VAug.ltw2v_wv",
@@ -434,7 +434,7 @@
"scope": "public",
"parent_class": "WordNetAug",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/augment/wordnet.py",
- "line": 205
+ "line": 209
},
{
"name": "pythainlp.chat.core.ChatBotModel.history",
@@ -511,21 +511,21 @@
"scope": "public",
"parent_class": "_ResponseWrapper",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/core.py",
- "line": 41
+ "line": 42
},
{
"name": "pythainlp.corpus.core._ResponseWrapper.headers",
"scope": "public",
"parent_class": "_ResponseWrapper",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/core.py",
- "line": 42
+ "line": 43
},
{
"name": "pythainlp.corpus.core._ResponseWrapper._content",
"scope": "private",
"parent_class": "_ResponseWrapper",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/core.py",
- "line": 43
+ "line": 44
},
{
"name": "pythainlp.el._multiel.MultiEL.model_name",
@@ -1680,23 +1680,17 @@
"scope": "public",
"parent_class": "_SentenceTransformersModel",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/wsd/core.py",
- "line": 40
+ "line": 45
},
{
"name": "pythainlp.wsd.core._SentenceTransformersModel.model",
"scope": "public",
"parent_class": "_SentenceTransformersModel",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/wsd/core.py",
- "line": 41
+ "line": 46
}
],
"module_variables_no_hints": [
- {
- "name": "pythainlp.ancient.aksonhan._dict_aksonhan",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/ancient/aksonhan.py",
- "line": 13
- },
{
"name": "pythainlp.ancient.aksonhan.unknown",
"scope": "public",
@@ -1715,167 +1709,17 @@
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/ancient/aksonhan.py",
"line": 20
},
- {
- "name": "pythainlp.ancient.aksonhan._set_aksonhan",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/ancient/aksonhan.py",
- "line": 21
- },
- {
- "name": "pythainlp.ancient.aksonhan._trie",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/ancient/aksonhan.py",
- "line": 22
- },
- {
- "name": "pythainlp.ancient.aksonhan._tokenizer",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/ancient/aksonhan.py",
- "line": 23
- },
- {
- "name": "pythainlp.ancient.aksonhan._dict_thai",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/ancient/aksonhan.py",
- "line": 24
- },
- {
- "name": "pythainlp.augment.lm.phayathaibert._MODEL_NAME",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/augment/lm/phayathaibert.py",
- "line": 15
- },
- {
- "name": "pythainlp.augment.lm.wangchanberta.model_name",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/augment/lm/wangchanberta.py",
- "line": 11
- },
- {
- "name": "pythainlp.augment.word2vec.ltw2v.Word2VecAug",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/augment/word2vec/ltw2v.py",
- "line": 14
- },
- {
- "name": "pythainlp.augment.word2vec.thai2fit.Word2VecAug",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/augment/word2vec/thai2fit.py",
- "line": 14
- },
- {
- "name": "pythainlp.augment.wordnet.__all__",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/augment/wordnet.py",
- "line": 8
- },
- {
- "name": "pythainlp.augment.wordnet.orchid",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/augment/wordnet.py",
- "line": 23
- },
- {
- "name": "pythainlp.benchmarks.__all__",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/benchmarks/__init__.py",
- "line": 6
- },
- {
- "name": "pythainlp.benchmarks.word_tokenization.SEPARATOR",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/benchmarks/word_tokenization.py",
- "line": 13
- },
- {
- "name": "pythainlp.benchmarks.word_tokenization.SURROUNDING_SEPS_RX",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/benchmarks/word_tokenization.py",
- "line": 16
- },
- {
- "name": "pythainlp.benchmarks.word_tokenization.MULTIPLE_SEPS_RX",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/benchmarks/word_tokenization.py",
- "line": 21
- },
- {
- "name": "pythainlp.benchmarks.word_tokenization.TAG_RX",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/benchmarks/word_tokenization.py",
- "line": 24
- },
- {
- "name": "pythainlp.benchmarks.word_tokenization.TAILING_SEP_RX",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/benchmarks/word_tokenization.py",
- "line": 27
- },
{
"name": "pythainlp.cli.stdout",
"scope": "public",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/cli/__init__.py",
- "line": 14
- },
- {
- "name": "pythainlp.cli.stderr",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/cli/__init__.py",
- "line": 15
- },
- {
- "name": "pythainlp.cli.COMMANDS",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/cli/__init__.py",
"line": 18
},
{
- "name": "pythainlp.cli.CLI_NAME",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/cli/__init__.py",
- "line": 22
- },
- {
- "name": "pythainlp.cli.COMMAND_MAP",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/cli/__init__.py",
- "line": 47
- },
- {
- "name": "pythainlp.cli.command",
+ "name": "pythainlp.cli.stderr",
"scope": "public",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/cli/__init__.py",
- "line": 58
- },
- {
- "name": "pythainlp.cli.tokenize.DEFAULT_SENT_TOKEN_SEPARATOR",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/cli/tokenize.py",
- "line": 25
- },
- {
- "name": "pythainlp.cli.tokenize.DEFAULT_SUBWORD_TOKEN_SEPARATOR",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/cli/tokenize.py",
- "line": 26
- },
- {
- "name": "pythainlp.cli.tokenize.DEFAULT_SYLLABLE_TOKEN_SEPARATOR",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/cli/tokenize.py",
- "line": 27
- },
- {
- "name": "pythainlp.cli.tokenize.DEFAULT_WORD_TOKEN_SEPARATOR",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/cli/tokenize.py",
- "line": 28
- },
- {
- "name": "pythainlp.coref.__all__",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/coref/__init__.py",
- "line": 6
+ "line": 19
},
{
"name": "pythainlp.coref.core._MODEL",
@@ -1883,132 +1727,6 @@
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/coref/core.py",
"line": 8
},
- {
- "name": "pythainlp.corpus.common.__all__",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py",
- "line": 15
- },
- {
- "name": "pythainlp.corpus.common._THAI_COUNTRIES_FILENAME",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py",
- "line": 37
- },
- {
- "name": "pythainlp.corpus.common._THAI_THAILAND_PROVINCES_FILENAME",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py",
- "line": 41
- },
- {
- "name": "pythainlp.corpus.common._THAI_SYLLABLES_FILENAME",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py",
- "line": 44
- },
- {
- "name": "pythainlp.corpus.common._THAI_WORDS_FILENAME",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py",
- "line": 47
- },
- {
- "name": "pythainlp.corpus.common._THAI_STOPWORDS_FILENAME",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py",
- "line": 50
- },
- {
- "name": "pythainlp.corpus.common._THAI_NEGATIONS_FILENAME",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py",
- "line": 53
- },
- {
- "name": "pythainlp.corpus.common._THAI_PROFANITY_WORDS_FILENAME",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py",
- "line": 56
- },
- {
- "name": "pythainlp.corpus.common._THAI_FAMLIY_NAMES_FILENAME",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py",
- "line": 59
- },
- {
- "name": "pythainlp.corpus.common._THAI_FEMALE_NAMES_FILENAME",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py",
- "line": 61
- },
- {
- "name": "pythainlp.corpus.common._THAI_MALE_NAMES_FILENAME",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py",
- "line": 63
- },
- {
- "name": "pythainlp.corpus.core._CHECK_MODE",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/core.py",
- "line": 25
- },
- {
- "name": "pythainlp.corpus.core._USER_AGENT",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/core.py",
- "line": 26
- },
- {
- "name": "pythainlp.corpus.icu._THAI_ICU_FILENAME",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/icu.py",
- "line": 10
- },
- {
- "name": "pythainlp.corpus.oscar.__all__",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/oscar.py",
- "line": 12
- },
- {
- "name": "pythainlp.corpus.oscar._OSCAR_FILENAME",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/oscar.py",
- "line": 18
- },
- {
- "name": "pythainlp.corpus.th_en_translit.__all__",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/th_en_translit.py",
- "line": 17
- },
- {
- "name": "pythainlp.corpus.th_en_translit._FILE_NAME",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/th_en_translit.py",
- "line": 23
- },
- {
- "name": "pythainlp.corpus.th_en_translit.TRANSLITERATE_EN",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/th_en_translit.py",
- "line": 24
- },
- {
- "name": "pythainlp.corpus.th_en_translit.TRANSLITERATE_FOLLOW_RTSG",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/th_en_translit.py",
- "line": 25
- },
- {
- "name": "pythainlp.corpus.th_en_translit.TRANSLITERATE_DICT",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/th_en_translit.py",
- "line": 80
- },
{
"name": "pythainlp.corpus.tnc.__all__",
"scope": "public",
@@ -2159,18 +1877,6 @@
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/lm/__init__.py",
"line": 5
},
- {
- "name": "pythainlp.morpheme.thaiwordcheck._TH_PREFIX_DIPHTHONG",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/morpheme/thaiwordcheck.py",
- "line": 64
- },
- {
- "name": "pythainlp.morpheme.thaiwordcheck._TH_CONSONANTS_PATTERN",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/morpheme/thaiwordcheck.py",
- "line": 68
- },
{
"name": "pythainlp.parse.core._tagger_name",
"scope": "private",
@@ -2201,24 +1907,6 @@
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/phayathaibert/core.py",
"line": 21
},
- {
- "name": "pythainlp.soundex.complete_soundex._complete_soundex_instance",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/soundex/complete_soundex.py",
- "line": 616
- },
- {
- "name": "pythainlp.soundex.sound._ft",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/soundex/sound.py",
- "line": 12
- },
- {
- "name": "pythainlp.soundex.sound._dst",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/soundex/sound.py",
- "line": 13
- },
{
"name": "pythainlp.spell.phunspell.pspell",
"scope": "public",
@@ -2633,42 +2321,6 @@
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/wtsplit.py",
"line": 18
},
- {
- "name": "pythainlp.tools.misspell.THAI_CHARACTERS_WITHOUT_SHIFT",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/tools/misspell.py",
- "line": 10
- },
- {
- "name": "pythainlp.tools.misspell.THAI_CHARACTERS_WITH_SHIFT",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/tools/misspell.py",
- "line": 17
- },
- {
- "name": "pythainlp.tools.misspell.ENGLISH_CHARACTERS_WITHOUT_SHIFT",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/tools/misspell.py",
- "line": 24
- },
- {
- "name": "pythainlp.tools.misspell.ENGLISH_CHARACTERS_WITH_SHIFT",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/tools/misspell.py",
- "line": 31
- },
- {
- "name": "pythainlp.tools.misspell.ALL_CHARACTERS",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/tools/misspell.py",
- "line": 39
- },
- {
- "name": "pythainlp.tools.path.PYTHAINLP_DEFAULT_DATA_DIR",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/tools/path.py",
- "line": 21
- },
{
"name": "pythainlp.translate.__all__",
"scope": "public",
@@ -3395,71 +3047,11 @@
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/wangchanberta/core.py",
"line": 17
},
- {
- "name": "pythainlp.word_vector.core.WV_DIM",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/word_vector/core.py",
- "line": 15
- },
- {
- "name": "pythainlp.word_vector.core._MODEL_NAME",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/word_vector/core.py",
- "line": 17
- },
- {
- "name": "pythainlp.word_vector.core._TK_SP",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/word_vector/core.py",
- "line": 19
- },
- {
- "name": "pythainlp.word_vector.core._TK_EOL",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/word_vector/core.py",
- "line": 20
- },
- {
- "name": "pythainlp.wsd.core._wsd_dict",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/wsd/core.py",
- "line": 12
- },
- {
- "name": "pythainlp.wsd.core._mean_all",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/wsd/core.py",
- "line": 13
- },
{
"name": "pythainlp.wsd.core.unknown",
"scope": "public",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/wsd/core.py",
- "line": 16
- },
- {
- "name": "pythainlp.wsd.core._all_word",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/wsd/core.py",
- "line": 18
- },
- {
- "name": "pythainlp.wsd.core._TRIE",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/wsd/core.py",
"line": 19
- },
- {
- "name": "pythainlp.wsd.core._word_cut",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/wsd/core.py",
- "line": 20
- },
- {
- "name": "pythainlp.wsd.core._MODEL",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/wsd/core.py",
- "line": 22
}
],
"type_aliases": []
diff --git a/pythainlp/corpus/th_en_translit.py b/pythainlp/corpus/th_en_translit.py
index 2ac4b3a3d..e618208d8 100644
--- a/pythainlp/corpus/th_en_translit.py
+++ b/pythainlp/corpus/th_en_translit.py
@@ -14,15 +14,15 @@
from importlib.resources import files
from typing import Union
-__all__ = [
+__all__: list[str] = [
"get_transliteration_dict",
"TRANSLITERATE_EN",
"TRANSLITERATE_FOLLOW_RTSG",
]
-_FILE_NAME = "th_en_transliteration_v1.4.tsv"
-TRANSLITERATE_EN = "en"
-TRANSLITERATE_FOLLOW_RTSG = "follow_rtsg"
+_FILE_NAME: str = "th_en_transliteration_v1.4.tsv"
+TRANSLITERATE_EN: str = "en"
+TRANSLITERATE_FOLLOW_RTSG: str = "follow_rtsg"
def get_transliteration_dict() -> defaultdict[
@@ -77,4 +77,6 @@ def get_transliteration_dict() -> defaultdict[
return trans_dict
-TRANSLITERATE_DICT = get_transliteration_dict()
+TRANSLITERATE_DICT: defaultdict[
+ str, dict[str, list[Union[str, bool, None]]]
+] = get_transliteration_dict()
diff --git a/pythainlp/morpheme/thaiwordcheck.py b/pythainlp/morpheme/thaiwordcheck.py
index 50f4eb44b..cbb36bbd5 100644
--- a/pythainlp/morpheme/thaiwordcheck.py
+++ b/pythainlp/morpheme/thaiwordcheck.py
@@ -17,7 +17,6 @@
from __future__ import annotations
import re
-from typing import Pattern
_THANTHAKHAT_CHAR: str = "\u0e4c" # Thanthakhat (cancellation of sound)
@@ -61,11 +60,11 @@
}
# Diphthong prefixes (can start native Thai word)
-_TH_PREFIX_DIPHTHONG = {"กะ", "กระ", "ปะ", "ประ"}
+_TH_PREFIX_DIPHTHONG: set[str] = {"กะ", "กระ", "ปะ", "ประ"}
# Thai consonant filter
# O ANG (U+0E2D) is omitted, as it can be considered as vowel
-_TH_CONSONANTS_PATTERN = re.compile(r"[ก-ฬฮ]", re.U)
+_TH_CONSONANTS_PATTERN: re.Pattern[str] = re.compile(r"[ก-ฬฮ]", re.U)
def is_native_thai(word: str) -> bool:
diff --git a/pythainlp/soundex/complete_soundex.py b/pythainlp/soundex/complete_soundex.py
index 7b5a28464..1ccafd463 100644
--- a/pythainlp/soundex/complete_soundex.py
+++ b/pythainlp/soundex/complete_soundex.py
@@ -45,7 +45,9 @@ class CompleteSoundex:
def __init__(self) -> None:
# Thai consonants for pattern matching
- self.thai_consonants: str = "กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬฮอ"
+ self.thai_consonants: str = (
+ "กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรลวศษสหฬฮอ"
+ )
# 1. Maps (Tables 5.1 - 5.4)
self.initial_map: dict[str, str] = {
@@ -613,7 +615,7 @@ def encode(self, text: str) -> str:
# Singleton instance for module-level function
-_complete_soundex_instance = None
+_complete_soundex_instance: "CompleteSoundex | None" = None
def complete_soundex(text: str) -> str:
diff --git a/pythainlp/soundex/sound.py b/pythainlp/soundex/sound.py
index f5065f6a9..f00dfdd38 100644
--- a/pythainlp/soundex/sound.py
+++ b/pythainlp/soundex/sound.py
@@ -9,8 +9,8 @@
from pythainlp.tokenize import word_tokenize
from pythainlp.transliterate import pronunciate, transliterate
-_ft = panphon.FeatureTable()
-_dst = panphon.distance.Distance()
+_ft: panphon.FeatureTable = panphon.FeatureTable()
+_dst: panphon.distance.Distance = panphon.distance.Distance()
def _clean_ipa(ipa: str) -> str:
diff --git a/pythainlp/soundex/udom83.py b/pythainlp/soundex/udom83.py
index 201a66830..0b0e88d5c 100644
--- a/pythainlp/soundex/udom83.py
+++ b/pythainlp/soundex/udom83.py
@@ -24,8 +24,12 @@
_THANTHAKHAT: str = "\u0e4c"
_RE_1: Pattern[str] = re.compile(r"รร([\u0e40-\u0e44])") # เ-ไ
-_RE_2: Pattern[str] = re.compile(f"รร([{thai_consonants}][{thai_consonants}\u0e40-\u0e44])")
-_RE_3: Pattern[str] = re.compile(f"รร([{thai_consonants}][\u0e30-\u0e39\u0e48-\u0e4c])")
+_RE_2: Pattern[str] = re.compile(
+ f"รร([{thai_consonants}][{thai_consonants}\u0e40-\u0e44])"
+)
+_RE_3: Pattern[str] = re.compile(
+ f"รร([{thai_consonants}][\u0e30-\u0e39\u0e48-\u0e4c])"
+)
_RE_4: Pattern[str] = re.compile(r"รร")
_RE_5: Pattern[str] = re.compile(f"ไ([{thai_consonants}]ย)")
_RE_6: Pattern[str] = re.compile(f"[ไใ]([{thai_consonants}])")
diff --git a/pythainlp/tools/misspell.py b/pythainlp/tools/misspell.py
index f455b4b07..07c736f50 100644
--- a/pythainlp/tools/misspell.py
+++ b/pythainlp/tools/misspell.py
@@ -7,28 +7,28 @@
import random
from typing import Optional
-THAI_CHARACTERS_WITHOUT_SHIFT = [
+THAI_CHARACTERS_WITHOUT_SHIFT: list[str] = [
"ผปแอิืทมใฝ",
"ฟหกดเ้่าสวง",
"ๆไำพะัีรนยบลฃ",
"ๅ/_ภถุึคตจขช",
]
-THAI_CHARACTERS_WITH_SHIFT = [
+THAI_CHARACTERS_WITH_SHIFT: list[str] = [
"()ฉฮฺ์?ฒฬฦ",
"ฤฆฏโฌ็๋ษศซ.",
'๐"ฎฑธํ๊ณฯญฐ,',
"+๑๒๓๔ู฿๕๖๗๘๙",
]
-ENGLISH_CHARACTERS_WITHOUT_SHIFT = [
+ENGLISH_CHARACTERS_WITHOUT_SHIFT: list[str] = [
"1234567890-=",
"qwertyuiop[]\\",
"asdfghjkl;'",
"zxcvbnm,./",
]
-ENGLISH_CHARACTERS_WITH_SHIFT = [
+ENGLISH_CHARACTERS_WITH_SHIFT: list[str] = [
"!@#$%^&*()_+",
"QWERTYUIOP{}|",
'ASDFGHJKL:"',
@@ -36,7 +36,7 @@
]
-ALL_CHARACTERS = [
+ALL_CHARACTERS: list[list[str]] = [
THAI_CHARACTERS_WITHOUT_SHIFT + THAI_CHARACTERS_WITH_SHIFT,
ENGLISH_CHARACTERS_WITHOUT_SHIFT + ENGLISH_CHARACTERS_WITH_SHIFT,
]
diff --git a/pythainlp/tools/path.py b/pythainlp/tools/path.py
index 68eaf11a3..131979220 100644
--- a/pythainlp/tools/path.py
+++ b/pythainlp/tools/path.py
@@ -18,7 +18,7 @@
else:
from importlib_resources import files # type: ignore[import-not-found,no-redef] # noqa: I001
-PYTHAINLP_DEFAULT_DATA_DIR = "pythainlp-data"
+PYTHAINLP_DEFAULT_DATA_DIR: str = "pythainlp-data"
def get_full_data_path(path: str) -> str:
diff --git a/pythainlp/word_vector/core.py b/pythainlp/word_vector/core.py
index 1fd7ee4ef..1eead813e 100644
--- a/pythainlp/word_vector/core.py
+++ b/pythainlp/word_vector/core.py
@@ -12,12 +12,12 @@
from gensim.models.keyedvectors import Word2VecKeyedVectors
from numpy import ndarray
-WV_DIM = 300 # word vector dimension
+WV_DIM: int = 300 # word vector dimension
-_MODEL_NAME = "thai2fit_wv"
+_MODEL_NAME: str = "thai2fit_wv"
-_TK_SP = "xxspace"
-_TK_EOL = "xxeol"
+_TK_SP: str = "xxspace"
+_TK_EOL: str = "xxeol"
class WordVector:
diff --git a/pythainlp/wsd/core.py b/pythainlp/wsd/core.py
index 8ab425872..0647f2a4a 100644
--- a/pythainlp/wsd/core.py
+++ b/pythainlp/wsd/core.py
@@ -3,23 +3,26 @@
# SPDX-License-Identifier: Apache-2.0
from __future__ import annotations
-from typing import Optional, cast
+from typing import TYPE_CHECKING, Optional, Union, cast
from pythainlp.corpus import thai_wsd_dict
from pythainlp.tokenize import Tokenizer
from pythainlp.util.trie import Trie
-_wsd_dict = thai_wsd_dict()
-_mean_all = {}
+if TYPE_CHECKING:
+ from typing import Any
+
+_wsd_dict: dict[str, Union[list[str], list[list[str]]]] = thai_wsd_dict()
+_mean_all: dict[str, Any] = {}
for i, j in zip(_wsd_dict["word"], _wsd_dict["meaning"]):
_mean_all[i] = j
-_all_word = cast(set[str], set(_mean_all.keys()))
-_TRIE = Trie(_all_word)
-_word_cut = Tokenizer(custom_dict=_TRIE)
+_all_word: set[str] = cast(set[str], set(_mean_all.keys()))
+_TRIE: Trie = Trie(_all_word)
+_word_cut: Tokenizer = Tokenizer(custom_dict=_TRIE)
-_MODEL = None
+_MODEL: Optional[Any] = None
class _SentenceTransformersModel:
@@ -32,7 +35,9 @@ def __init__(
self.device: str = device
self.model_name: str = model
- self.model: SentenceTransformer = SentenceTransformer(self.model_name, device=self.device) # type: ignore[assignment]
+ self.model: SentenceTransformer = SentenceTransformer(
+ self.model_name, device=self.device
+ ) # type: ignore[assignment]
def change_device(self, device: str) -> None:
from sentence_transformers import SentenceTransformer
From f417160aac68321fa1bb0c76313c4d985bc28e95 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 4 Feb 2026 08:18:15 +0000
Subject: [PATCH 05/17] Add type hints to remaining small module variables
Added type annotations to module-level variables in:
- el/__init__.py
- lm/__init__.py
- parse/core.py
- summarize/freq.py
- tag/thai_nner.py, thainer.py
- tokenize/pyicu.py
- transliterate/pyicu.py
Progress: Variables type coverage improved from 62.52% to 63.29% (738/1166)
Co-authored-by: bact <128572+bact@users.noreply.github.com>
---
.../output/instance_variables_no_hints.csv | 18 ++---
.../output/module_variables_no_hints.csv | 74 +------------------
.../analysis/output/submodule_summary.csv | 56 +++++++-------
.../analysis/output/type_hint_analysis.json | 62 +---------------
pythainlp/el/__init__.py | 2 +-
pythainlp/el/_multiel.py | 2 +-
pythainlp/el/core.py | 4 +-
pythainlp/lm/__init__.py | 2 +-
pythainlp/parse/core.py | 2 +-
pythainlp/parse/transformers_ud.py | 6 +-
pythainlp/parse/ud_goeswith.py | 4 +-
pythainlp/summarize/freq.py | 6 +-
pythainlp/summarize/mt5.py | 4 +-
pythainlp/tag/thai_nner.py | 62 ++++++++++------
pythainlp/tag/thainer.py | 4 +-
pythainlp/tokenize/pyicu.py | 2 +-
pythainlp/transliterate/pyicu.py | 4 +-
17 files changed, 109 insertions(+), 205 deletions(-)
diff --git a/build_tools/analysis/output/instance_variables_no_hints.csv b/build_tools/analysis/output/instance_variables_no_hints.csv
index 7b512c5bb..1812c0611 100644
--- a/build_tools/analysis/output/instance_variables_no_hints.csv
+++ b/build_tools/analysis/output/instance_variables_no_hints.csv
@@ -1,6 +1,6 @@
Variable Name,Submodule,Parent Class,Scope,File,Line
-pythainlp.augment.lm.fasttext.FastTextAug.model,augment,FastTextAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/lm/fasttext.py,35
pythainlp.augment.lm.fasttext.FastTextAug.model,augment,FastTextAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/lm/fasttext.py,37
+pythainlp.augment.lm.fasttext.FastTextAug.model,augment,FastTextAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/lm/fasttext.py,39
pythainlp.augment.lm.phayathaibert.ThaiTextAugmenter.tokenizer,augment,ThaiTextAugmenter,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/lm/phayathaibert.py,31
pythainlp.augment.lm.phayathaibert.ThaiTextAugmenter.model_for_masked_lm,augment,ThaiTextAugmenter,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/lm/phayathaibert.py,32
pythainlp.augment.lm.phayathaibert.ThaiTextAugmenter.model,augment,ThaiTextAugmenter,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/lm/phayathaibert.py,35
@@ -18,8 +18,8 @@ pythainlp.augment.word2vec.bpemb_wv.BPEmbAug.sentence,augment,BPEmbAug,public,/h
pythainlp.augment.word2vec.bpemb_wv.BPEmbAug.temp,augment,BPEmbAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/word2vec/bpemb_wv.py,72
pythainlp.augment.word2vec.bpemb_wv.BPEmbAug.temp_new,augment,BPEmbAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/word2vec/bpemb_wv.py,73
pythainlp.augment.word2vec.bpemb_wv.BPEmbAug.t,augment,BPEmbAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/word2vec/bpemb_wv.py,75
-pythainlp.augment.word2vec.core.Word2VecAug.model,augment,Word2VecAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/word2vec/core.py,34
-pythainlp.augment.word2vec.core.Word2VecAug.model,augment,Word2VecAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/word2vec/core.py,38
+pythainlp.augment.word2vec.core.Word2VecAug.model,augment,Word2VecAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/word2vec/core.py,36
+pythainlp.augment.word2vec.core.Word2VecAug.model,augment,Word2VecAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/word2vec/core.py,40
pythainlp.augment.word2vec.ltw2v.LTW2VAug.ltw2v_wv,augment,LTW2VAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/word2vec/ltw2v.py,30
pythainlp.augment.word2vec.ltw2v.LTW2VAug.aug,augment,LTW2VAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/word2vec/ltw2v.py,46
pythainlp.augment.word2vec.thai2fit.Thai2fitAug.thai2fit_wv,augment,Thai2fitAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/word2vec/thai2fit.py,30
@@ -28,7 +28,7 @@ pythainlp.augment.wordnet.WordNetAug.list_synsets,augment,WordNetAug,public,/hom
pythainlp.augment.wordnet.WordNetAug.p2w_pos,augment,WordNetAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/wordnet.py,142
pythainlp.augment.wordnet.WordNetAug.list_synsets,augment,WordNetAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/wordnet.py,144
pythainlp.augment.wordnet.WordNetAug.list_synsets,augment,WordNetAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/wordnet.py,146
-pythainlp.augment.wordnet.WordNetAug.temp,augment,WordNetAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/wordnet.py,205
+pythainlp.augment.wordnet.WordNetAug.temp,augment,WordNetAug,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/wordnet.py,209
pythainlp.chat.core.ChatBotModel.history,chat,ChatBotModel,public,/home/runner/work/pythainlp/pythainlp/pythainlp/chat/core.py,16
pythainlp.chat.core.ChatBotModel.model,chat,ChatBotModel,public,/home/runner/work/pythainlp/pythainlp/pythainlp/chat/core.py,41
pythainlp.classify.param_free.GzipModel.training_data,classify,GzipModel,public,/home/runner/work/pythainlp/pythainlp/pythainlp/classify/param_free.py,36
@@ -39,9 +39,9 @@ pythainlp.cli.tag.SubAppBase.args,cli,SubAppBase,public,/home/runner/work/pythai
pythainlp.cli.tag.POSTaggingApp.separator,cli,POSTaggingApp,public,/home/runner/work/pythainlp/pythainlp/pythainlp/cli/tag.py,55
pythainlp.cli.tag.POSTaggingApp.run,cli,POSTaggingApp,public,/home/runner/work/pythainlp/pythainlp/pythainlp/cli/tag.py,56
pythainlp.cli.tokenize.SubAppBase.args,cli,SubAppBase,public,/home/runner/work/pythainlp/pythainlp/pythainlp/cli/tokenize.py,77
-pythainlp.corpus.core._ResponseWrapper.status_code,corpus,_ResponseWrapper,public,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/core.py,41
-pythainlp.corpus.core._ResponseWrapper.headers,corpus,_ResponseWrapper,public,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/core.py,42
-pythainlp.corpus.core._ResponseWrapper._content,corpus,_ResponseWrapper,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/core.py,43
+pythainlp.corpus.core._ResponseWrapper.status_code,corpus,_ResponseWrapper,public,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/core.py,42
+pythainlp.corpus.core._ResponseWrapper.headers,corpus,_ResponseWrapper,public,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/core.py,43
+pythainlp.corpus.core._ResponseWrapper._content,corpus,_ResponseWrapper,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/core.py,44
pythainlp.el._multiel.MultiEL.model_name,el,MultiEL,public,/home/runner/work/pythainlp/pythainlp/pythainlp/el/_multiel.py,18
pythainlp.el._multiel.MultiEL.device,el,MultiEL,public,/home/runner/work/pythainlp/pythainlp/pythainlp/el/_multiel.py,19
pythainlp.el._multiel.MultiEL._bela_run,el,MultiEL,private,/home/runner/work/pythainlp/pythainlp/pythainlp/el/_multiel.py,29
@@ -206,5 +206,5 @@ pythainlp.wangchanberta.core.ThaiNameTagger.sent_ner,wangchanberta,ThaiNameTagge
pythainlp.wangchanberta.core.ThaiNameTagger.sent_ner,wangchanberta,ThaiNameTagger,public,/home/runner/work/pythainlp/pythainlp/pythainlp/wangchanberta/core.py,126
pythainlp.word_vector.core.WordVector.tokenize,word_vector,WordVector,public,/home/runner/work/pythainlp/pythainlp/pythainlp/word_vector/core.py,68
pythainlp.word_vector.core.WordVector.tokenize,word_vector,WordVector,public,/home/runner/work/pythainlp/pythainlp/pythainlp/word_vector/core.py,70
-pythainlp.wsd.core._SentenceTransformersModel.device,wsd,_SentenceTransformersModel,public,/home/runner/work/pythainlp/pythainlp/pythainlp/wsd/core.py,40
-pythainlp.wsd.core._SentenceTransformersModel.model,wsd,_SentenceTransformersModel,public,/home/runner/work/pythainlp/pythainlp/pythainlp/wsd/core.py,41
+pythainlp.wsd.core._SentenceTransformersModel.device,wsd,_SentenceTransformersModel,public,/home/runner/work/pythainlp/pythainlp/pythainlp/wsd/core.py,45
+pythainlp.wsd.core._SentenceTransformersModel.model,wsd,_SentenceTransformersModel,public,/home/runner/work/pythainlp/pythainlp/pythainlp/wsd/core.py,46
diff --git a/build_tools/analysis/output/module_variables_no_hints.csv b/build_tools/analysis/output/module_variables_no_hints.csv
index 53ae4af91..88e8ed985 100644
--- a/build_tools/analysis/output/module_variables_no_hints.csv
+++ b/build_tools/analysis/output/module_variables_no_hints.csv
@@ -1,57 +1,10 @@
Variable Name,Submodule,Scope,File,Line
-pythainlp.ancient.aksonhan._dict_aksonhan,ancient,private,/home/runner/work/pythainlp/pythainlp/pythainlp/ancient/aksonhan.py,13
pythainlp.ancient.aksonhan.unknown,ancient,public,/home/runner/work/pythainlp/pythainlp/pythainlp/ancient/aksonhan.py,18
pythainlp.ancient.aksonhan.unknown,ancient,public,/home/runner/work/pythainlp/pythainlp/pythainlp/ancient/aksonhan.py,19
pythainlp.ancient.aksonhan.unknown,ancient,public,/home/runner/work/pythainlp/pythainlp/pythainlp/ancient/aksonhan.py,20
-pythainlp.ancient.aksonhan._set_aksonhan,ancient,private,/home/runner/work/pythainlp/pythainlp/pythainlp/ancient/aksonhan.py,21
-pythainlp.ancient.aksonhan._trie,ancient,private,/home/runner/work/pythainlp/pythainlp/pythainlp/ancient/aksonhan.py,22
-pythainlp.ancient.aksonhan._tokenizer,ancient,private,/home/runner/work/pythainlp/pythainlp/pythainlp/ancient/aksonhan.py,23
-pythainlp.ancient.aksonhan._dict_thai,ancient,private,/home/runner/work/pythainlp/pythainlp/pythainlp/ancient/aksonhan.py,24
-pythainlp.augment.lm.phayathaibert._MODEL_NAME,augment,private,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/lm/phayathaibert.py,15
-pythainlp.augment.lm.wangchanberta.model_name,augment,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/lm/wangchanberta.py,11
-pythainlp.augment.word2vec.ltw2v.Word2VecAug,augment,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/word2vec/ltw2v.py,14
-pythainlp.augment.word2vec.thai2fit.Word2VecAug,augment,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/word2vec/thai2fit.py,14
-pythainlp.augment.wordnet.__all__,augment,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/wordnet.py,8
-pythainlp.augment.wordnet.orchid,augment,public,/home/runner/work/pythainlp/pythainlp/pythainlp/augment/wordnet.py,23
-pythainlp.benchmarks.__all__,benchmarks,public,/home/runner/work/pythainlp/pythainlp/pythainlp/benchmarks/__init__.py,6
-pythainlp.benchmarks.word_tokenization.SEPARATOR,benchmarks,public,/home/runner/work/pythainlp/pythainlp/pythainlp/benchmarks/word_tokenization.py,13
-pythainlp.benchmarks.word_tokenization.SURROUNDING_SEPS_RX,benchmarks,public,/home/runner/work/pythainlp/pythainlp/pythainlp/benchmarks/word_tokenization.py,16
-pythainlp.benchmarks.word_tokenization.MULTIPLE_SEPS_RX,benchmarks,public,/home/runner/work/pythainlp/pythainlp/pythainlp/benchmarks/word_tokenization.py,21
-pythainlp.benchmarks.word_tokenization.TAG_RX,benchmarks,public,/home/runner/work/pythainlp/pythainlp/pythainlp/benchmarks/word_tokenization.py,24
-pythainlp.benchmarks.word_tokenization.TAILING_SEP_RX,benchmarks,public,/home/runner/work/pythainlp/pythainlp/pythainlp/benchmarks/word_tokenization.py,27
-pythainlp.cli.stdout,cli,public,/home/runner/work/pythainlp/pythainlp/pythainlp/cli/__init__.py,14
-pythainlp.cli.stderr,cli,public,/home/runner/work/pythainlp/pythainlp/pythainlp/cli/__init__.py,15
-pythainlp.cli.COMMANDS,cli,public,/home/runner/work/pythainlp/pythainlp/pythainlp/cli/__init__.py,18
-pythainlp.cli.CLI_NAME,cli,public,/home/runner/work/pythainlp/pythainlp/pythainlp/cli/__init__.py,22
-pythainlp.cli.COMMAND_MAP,cli,public,/home/runner/work/pythainlp/pythainlp/pythainlp/cli/__init__.py,47
-pythainlp.cli.command,cli,public,/home/runner/work/pythainlp/pythainlp/pythainlp/cli/__init__.py,58
-pythainlp.cli.tokenize.DEFAULT_SENT_TOKEN_SEPARATOR,cli,public,/home/runner/work/pythainlp/pythainlp/pythainlp/cli/tokenize.py,25
-pythainlp.cli.tokenize.DEFAULT_SUBWORD_TOKEN_SEPARATOR,cli,public,/home/runner/work/pythainlp/pythainlp/pythainlp/cli/tokenize.py,26
-pythainlp.cli.tokenize.DEFAULT_SYLLABLE_TOKEN_SEPARATOR,cli,public,/home/runner/work/pythainlp/pythainlp/pythainlp/cli/tokenize.py,27
-pythainlp.cli.tokenize.DEFAULT_WORD_TOKEN_SEPARATOR,cli,public,/home/runner/work/pythainlp/pythainlp/pythainlp/cli/tokenize.py,28
-pythainlp.coref.__all__,coref,public,/home/runner/work/pythainlp/pythainlp/pythainlp/coref/__init__.py,6
+pythainlp.cli.stdout,cli,public,/home/runner/work/pythainlp/pythainlp/pythainlp/cli/__init__.py,18
+pythainlp.cli.stderr,cli,public,/home/runner/work/pythainlp/pythainlp/pythainlp/cli/__init__.py,19
pythainlp.coref.core._MODEL,coref,private,/home/runner/work/pythainlp/pythainlp/pythainlp/coref/core.py,8
-pythainlp.corpus.common.__all__,corpus,public,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py,15
-pythainlp.corpus.common._THAI_COUNTRIES_FILENAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py,37
-pythainlp.corpus.common._THAI_THAILAND_PROVINCES_FILENAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py,41
-pythainlp.corpus.common._THAI_SYLLABLES_FILENAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py,44
-pythainlp.corpus.common._THAI_WORDS_FILENAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py,47
-pythainlp.corpus.common._THAI_STOPWORDS_FILENAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py,50
-pythainlp.corpus.common._THAI_NEGATIONS_FILENAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py,53
-pythainlp.corpus.common._THAI_PROFANITY_WORDS_FILENAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py,56
-pythainlp.corpus.common._THAI_FAMLIY_NAMES_FILENAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py,59
-pythainlp.corpus.common._THAI_FEMALE_NAMES_FILENAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py,61
-pythainlp.corpus.common._THAI_MALE_NAMES_FILENAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/common.py,63
-pythainlp.corpus.core._CHECK_MODE,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/core.py,25
-pythainlp.corpus.core._USER_AGENT,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/core.py,26
-pythainlp.corpus.icu._THAI_ICU_FILENAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/icu.py,10
-pythainlp.corpus.oscar.__all__,corpus,public,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/oscar.py,12
-pythainlp.corpus.oscar._OSCAR_FILENAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/oscar.py,18
-pythainlp.corpus.th_en_translit.__all__,corpus,public,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/th_en_translit.py,17
-pythainlp.corpus.th_en_translit._FILE_NAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/th_en_translit.py,23
-pythainlp.corpus.th_en_translit.TRANSLITERATE_EN,corpus,public,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/th_en_translit.py,24
-pythainlp.corpus.th_en_translit.TRANSLITERATE_FOLLOW_RTSG,corpus,public,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/th_en_translit.py,25
-pythainlp.corpus.th_en_translit.TRANSLITERATE_DICT,corpus,public,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/th_en_translit.py,80
pythainlp.corpus.tnc.__all__,corpus,public,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/tnc.py,8
pythainlp.corpus.tnc._UNIGRAM_FILENAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/tnc.py,19
pythainlp.corpus.tnc._BIGRAM_CORPUS_NAME,corpus,private,/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/tnc.py,20
@@ -77,16 +30,11 @@ pythainlp.generate.thai2fit.config,generate,public,/home/runner/work/pythainlp/p
pythainlp.generate.thai2fit.trn_args,generate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/generate/thai2fit.py,99
pythainlp.generate.thai2fit.learn,generate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/generate/thai2fit.py,101
pythainlp.lm.__all__,lm,public,/home/runner/work/pythainlp/pythainlp/pythainlp/lm/__init__.py,5
-pythainlp.morpheme.thaiwordcheck._TH_PREFIX_DIPHTHONG,morpheme,private,/home/runner/work/pythainlp/pythainlp/pythainlp/morpheme/thaiwordcheck.py,64
-pythainlp.morpheme.thaiwordcheck._TH_CONSONANTS_PATTERN,morpheme,private,/home/runner/work/pythainlp/pythainlp/pythainlp/morpheme/thaiwordcheck.py,68
pythainlp.parse.core._tagger_name,parse,private,/home/runner/work/pythainlp/pythainlp/pythainlp/parse/core.py,9
pythainlp.phayathaibert.__all__,phayathaibert,public,/home/runner/work/pythainlp/pythainlp/pythainlp/phayathaibert/__init__.py,6
pythainlp.phayathaibert.core._PAT_URL,phayathaibert,private,/home/runner/work/pythainlp/pythainlp/pythainlp/phayathaibert/core.py,18
pythainlp.phayathaibert.core._model_name,phayathaibert,private,/home/runner/work/pythainlp/pythainlp/pythainlp/phayathaibert/core.py,20
pythainlp.phayathaibert.core._tokenizer,phayathaibert,private,/home/runner/work/pythainlp/pythainlp/pythainlp/phayathaibert/core.py,21
-pythainlp.soundex.complete_soundex._complete_soundex_instance,soundex,private,/home/runner/work/pythainlp/pythainlp/pythainlp/soundex/complete_soundex.py,616
-pythainlp.soundex.sound._ft,soundex,private,/home/runner/work/pythainlp/pythainlp/pythainlp/soundex/sound.py,12
-pythainlp.soundex.sound._dst,soundex,private,/home/runner/work/pythainlp/pythainlp/pythainlp/soundex/sound.py,13
pythainlp.spell.phunspell.pspell,spell,public,/home/runner/work/pythainlp/pythainlp/pythainlp/spell/phunspell.py,22
pythainlp.spell.symspellpy._UNIGRAM_FILENAME,spell,private,/home/runner/work/pythainlp/pythainlp/pythainlp/spell/symspellpy.py,28
pythainlp.spell.symspellpy._BIGRAM_CORPUS_NAME,spell,private,/home/runner/work/pythainlp/pythainlp/pythainlp/spell/symspellpy.py,29
@@ -156,12 +104,6 @@ pythainlp.tokenize.tcc_p._PAT_TCC,tokenize,private,/home/runner/work/pythainlp/p
pythainlp.tokenize.wtsplit._MODEL,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/wtsplit.py,16
pythainlp.tokenize.wtsplit._MODEL_NAME,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/wtsplit.py,17
pythainlp.tokenize.wtsplit._model_lock,tokenize,private,/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/wtsplit.py,18
-pythainlp.tools.misspell.THAI_CHARACTERS_WITHOUT_SHIFT,tools,public,/home/runner/work/pythainlp/pythainlp/pythainlp/tools/misspell.py,10
-pythainlp.tools.misspell.THAI_CHARACTERS_WITH_SHIFT,tools,public,/home/runner/work/pythainlp/pythainlp/pythainlp/tools/misspell.py,17
-pythainlp.tools.misspell.ENGLISH_CHARACTERS_WITHOUT_SHIFT,tools,public,/home/runner/work/pythainlp/pythainlp/pythainlp/tools/misspell.py,24
-pythainlp.tools.misspell.ENGLISH_CHARACTERS_WITH_SHIFT,tools,public,/home/runner/work/pythainlp/pythainlp/pythainlp/tools/misspell.py,31
-pythainlp.tools.misspell.ALL_CHARACTERS,tools,public,/home/runner/work/pythainlp/pythainlp/pythainlp/tools/misspell.py,39
-pythainlp.tools.path.PYTHAINLP_DEFAULT_DATA_DIR,tools,public,/home/runner/work/pythainlp/pythainlp/pythainlp/tools/path.py,21
pythainlp.translate.__all__,translate,public,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/__init__.py,6
pythainlp.translate.en_th._EN_TH_MODEL_NAME,translate,private,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/en_th.py,32
pythainlp.translate.en_th._EN_TH_FILE_NAME,translate,private,/home/runner/work/pythainlp/pythainlp/pythainlp/translate/en_th.py,34
@@ -283,14 +225,4 @@ pythainlp.util.time._THAI_TIME_AFFIX,util,private,/home/runner/work/pythainlp/py
pythainlp.wangchanberta.__all__,wangchanberta,public,/home/runner/work/pythainlp/pythainlp/pythainlp/wangchanberta/__init__.py,4
pythainlp.wangchanberta.core._model_name,wangchanberta,private,/home/runner/work/pythainlp/pythainlp/pythainlp/wangchanberta/core.py,16
pythainlp.wangchanberta.core._tokenizer,wangchanberta,private,/home/runner/work/pythainlp/pythainlp/pythainlp/wangchanberta/core.py,17
-pythainlp.word_vector.core.WV_DIM,word_vector,public,/home/runner/work/pythainlp/pythainlp/pythainlp/word_vector/core.py,15
-pythainlp.word_vector.core._MODEL_NAME,word_vector,private,/home/runner/work/pythainlp/pythainlp/pythainlp/word_vector/core.py,17
-pythainlp.word_vector.core._TK_SP,word_vector,private,/home/runner/work/pythainlp/pythainlp/pythainlp/word_vector/core.py,19
-pythainlp.word_vector.core._TK_EOL,word_vector,private,/home/runner/work/pythainlp/pythainlp/pythainlp/word_vector/core.py,20
-pythainlp.wsd.core._wsd_dict,wsd,private,/home/runner/work/pythainlp/pythainlp/pythainlp/wsd/core.py,12
-pythainlp.wsd.core._mean_all,wsd,private,/home/runner/work/pythainlp/pythainlp/pythainlp/wsd/core.py,13
-pythainlp.wsd.core.unknown,wsd,public,/home/runner/work/pythainlp/pythainlp/pythainlp/wsd/core.py,16
-pythainlp.wsd.core._all_word,wsd,private,/home/runner/work/pythainlp/pythainlp/pythainlp/wsd/core.py,18
-pythainlp.wsd.core._TRIE,wsd,private,/home/runner/work/pythainlp/pythainlp/pythainlp/wsd/core.py,19
-pythainlp.wsd.core._word_cut,wsd,private,/home/runner/work/pythainlp/pythainlp/pythainlp/wsd/core.py,20
-pythainlp.wsd.core._MODEL,wsd,private,/home/runner/work/pythainlp/pythainlp/pythainlp/wsd/core.py,22
+pythainlp.wsd.core.unknown,wsd,public,/home/runner/work/pythainlp/pythainlp/pythainlp/wsd/core.py,19
diff --git a/build_tools/analysis/output/submodule_summary.csv b/build_tools/analysis/output/submodule_summary.csv
index 06e7dace0..39f9f8c32 100644
--- a/build_tools/analysis/output/submodule_summary.csv
+++ b/build_tools/analysis/output/submodule_summary.csv
@@ -1,32 +1,32 @@
Submodule,Total,Complete,Incomplete,None,% Complete,Mypy Errors
__main__,1,1,0,0,100.00%,0
-ancient,2,2,0,0,100.00%,0
-augment,29,29,0,0,100.00%,0
-benchmarks,8,8,0,0,100.00%,0
-chat,4,4,0,0,100.00%,0
-classify,5,5,0,0,100.00%,0
-cli,21,21,0,0,100.00%,0
-coref,5,5,0,0,100.00%,0
-corpus,70,70,0,0,100.00%,0
-el,5,5,0,0,100.00%,0
-generate,15,15,0,0,100.00%,0
-khavee,9,9,0,0,100.00%,0
-lm,2,2,0,0,100.00%,0
-morpheme,2,2,0,0,100.00%,0
-parse,9,9,0,0,100.00%,0
-phayathaibert,19,19,0,0,100.00%,0
-soundex,27,27,0,0,100.00%,0
-spell,43,43,0,0,100.00%,0
-summarize,17,17,0,0,100.00%,0
-tag,73,73,0,0,100.00%,0
-tokenize,73,73,0,0,100.00%,0
+ancient,2,2,0,0,100.00%,26
+augment,29,29,0,0,100.00%,33
+benchmarks,8,8,0,0,100.00%,26
+chat,4,4,0,0,100.00%,28
+classify,5,5,0,0,100.00%,26
+cli,21,21,0,0,100.00%,28
+coref,5,5,0,0,100.00%,26
+corpus,70,70,0,0,100.00%,26
+el,5,5,0,0,100.00%,26
+generate,15,15,0,0,100.00%,31
+khavee,9,9,0,0,100.00%,26
+lm,2,2,0,0,100.00%,26
+morpheme,2,2,0,0,100.00%,26
+parse,9,9,0,0,100.00%,28
+phayathaibert,19,19,0,0,100.00%,26
+soundex,27,27,0,0,100.00%,26
+spell,43,43,0,0,100.00%,26
+summarize,17,17,0,0,100.00%,31
+tag,73,73,0,0,100.00%,28
+tokenize,73,73,0,0,100.00%,26
tokenizeicu,3,3,0,0,100.00%,0
-tools,9,9,0,0,100.00%,0
-translate,44,44,0,0,100.00%,0
-transliterate,75,75,0,0,100.00%,0
+tools,9,9,0,0,100.00%,26
+translate,44,44,0,0,100.00%,33
+transliterate,75,75,0,0,100.00%,27
transliterateicu,1,1,0,0,100.00%,0
-ulmfit,25,25,0,0,100.00%,0
-util,109,109,0,0,100.00%,0
-wangchanberta,9,9,0,0,100.00%,0
-word_vector,7,7,0,0,100.00%,0
-wsd,4,4,0,0,100.00%,0
+ulmfit,25,25,0,0,100.00%,30
+util,109,109,0,0,100.00%,26
+wangchanberta,9,9,0,0,100.00%,26
+word_vector,7,7,0,0,100.00%,33
+wsd,4,4,0,0,100.00%,28
diff --git a/build_tools/analysis/output/type_hint_analysis.json b/build_tools/analysis/output/type_hint_analysis.json
index fb82d0cc0..971bf481a 100644
--- a/build_tools/analysis/output/type_hint_analysis.json
+++ b/build_tools/analysis/output/type_hint_analysis.json
@@ -11,10 +11,10 @@
},
"variables": {
"total": 1166,
- "complete": 729,
- "none": 437,
- "pct_complete": 62.52144082332761,
- "pct_none": 37.478559176672384,
+ "complete": 738,
+ "none": 428,
+ "pct_complete": 63.293310463121784,
+ "pct_none": 36.706689536878216,
"class_variables": 216,
"instance_variables": 439,
"module_variables": 511
@@ -1787,12 +1787,6 @@
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/wikipedia.py",
"line": 11
},
- {
- "name": "pythainlp.el.__all__",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/el/__init__.py",
- "line": 6
- },
{
"name": "pythainlp.generate.__all__",
"scope": "public",
@@ -1871,18 +1865,6 @@
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/generate/thai2fit.py",
"line": 101
},
- {
- "name": "pythainlp.lm.__all__",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/lm/__init__.py",
- "line": 5
- },
- {
- "name": "pythainlp.parse.core._tagger_name",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/parse/core.py",
- "line": 9
- },
{
"name": "pythainlp.phayathaibert.__all__",
"scope": "public",
@@ -1997,30 +1979,6 @@
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/words_spelling_correction.py",
"line": 271
},
- {
- "name": "pythainlp.summarize.freq._STOPWORDS",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/summarize/freq.py",
- "line": 16
- },
- {
- "name": "pythainlp.tag.thai_nner.__all__",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/tag/thai_nner.py",
- "line": 18
- },
- {
- "name": "pythainlp.tag.thainer.__all__",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/tag/thainer.py",
- "line": 8
- },
- {
- "name": "pythainlp.tag.thainer._TOKENIZER_ENGINE",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/tag/thainer.py",
- "line": 21
- },
{
"name": "pythainlp.tokenize._utils._DIGITS_WITH_SEPARATOR",
"scope": "private",
@@ -2261,12 +2219,6 @@
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/oskut.py",
"line": 20
},
- {
- "name": "pythainlp.tokenizeicu._thread_local",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/tokenize/pyicu.py",
- "line": 21
- },
{
"name": "pythainlp.tokenize.sefr_cut._DEFAULT_ENGINE",
"scope": "private",
@@ -2405,12 +2357,6 @@
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/lookup.py",
"line": 22
},
- {
- "name": "pythainlp.transliterateicu._ICU_THAI_TO_LATIN",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/pyicu.py",
- "line": 16
- },
{
"name": "pythainlp.transliterate.royin._vowel_patterns",
"scope": "private",
diff --git a/pythainlp/el/__init__.py b/pythainlp/el/__init__.py
index 1a31a56bc..a4397da7d 100644
--- a/pythainlp/el/__init__.py
+++ b/pythainlp/el/__init__.py
@@ -3,6 +3,6 @@
# SPDX-License-Identifier: Apache-2.0
"""pythainlp.el"""
-__all__ = ["EntityLinker"]
+__all__: list[str] = ["EntityLinker"]
from pythainlp.el.core import EntityLinker
diff --git a/pythainlp/el/_multiel.py b/pythainlp/el/_multiel.py
index 135d4c763..f771b28b1 100644
--- a/pythainlp/el/_multiel.py
+++ b/pythainlp/el/_multiel.py
@@ -3,7 +3,7 @@
# SPDX-License-Identifier: Apache-2.0
from __future__ import annotations
-from typing import TYPE_CHECKING, Any, Union
+from typing import TYPE_CHECKING, Union
if TYPE_CHECKING:
from multiel import BELA
diff --git a/pythainlp/el/core.py b/pythainlp/el/core.py
index c393c2773..cdf1d438c 100644
--- a/pythainlp/el/core.py
+++ b/pythainlp/el/core.py
@@ -35,7 +35,9 @@ def __init__(
)
from pythainlp.el._multiel import MultiEL
- self.model: MultiEL = MultiEL(model_name=self.model_name, device=self.device)
+ self.model: MultiEL = MultiEL(
+ model_name=self.model_name, device=self.device
+ )
def get_el(
self, list_text: Union[list[str], str]
diff --git a/pythainlp/lm/__init__.py b/pythainlp/lm/__init__.py
index 259f101d2..8f72a7d70 100644
--- a/pythainlp/lm/__init__.py
+++ b/pythainlp/lm/__init__.py
@@ -2,7 +2,7 @@
# SPDX-FileType: SOURCE
# SPDX-License-Identifier: Apache-2.0
-__all__ = ["calculate_ngram_counts", "remove_repeated_ngrams"]
+__all__: list[str] = ["calculate_ngram_counts", "remove_repeated_ngrams"]
from pythainlp.lm.text_util import (
calculate_ngram_counts,
diff --git a/pythainlp/parse/core.py b/pythainlp/parse/core.py
index b02e0273c..836134c65 100644
--- a/pythainlp/parse/core.py
+++ b/pythainlp/parse/core.py
@@ -6,7 +6,7 @@
from typing import Any, List, Optional, Union
_tagger: Optional[Any] = None
-_tagger_name = ""
+_tagger_name: str = ""
def dependency_parsing(
diff --git a/pythainlp/parse/transformers_ud.py b/pythainlp/parse/transformers_ud.py
index fc5aac53c..7105cee03 100644
--- a/pythainlp/parse/transformers_ud.py
+++ b/pythainlp/parse/transformers_ud.py
@@ -16,8 +16,8 @@
if TYPE_CHECKING:
from transformers import (
- AutoTokenizer,
AutoModelForQuestionAnswering,
+ AutoTokenizer,
TokenClassificationPipeline,
)
@@ -38,7 +38,9 @@ def __init__(
if model is None:
model = "KoichiYasuoka/deberta-base-thai-ud-head"
self.tokenizer: AutoTokenizer = AutoTokenizer.from_pretrained(model)
- self.model: AutoModelForQuestionAnswering = AutoModelForQuestionAnswering.from_pretrained(model)
+ self.model: AutoModelForQuestionAnswering = (
+ AutoModelForQuestionAnswering.from_pretrained(model)
+ )
x = AutoModelForTokenClassification.from_pretrained
if os.path.isdir(model):
d, t = (
diff --git a/pythainlp/parse/ud_goeswith.py b/pythainlp/parse/ud_goeswith.py
index e2fb3c02a..58a10bfb8 100644
--- a/pythainlp/parse/ud_goeswith.py
+++ b/pythainlp/parse/ud_goeswith.py
@@ -29,7 +29,9 @@ def __init__(
if model is None:
model = "KoichiYasuoka/deberta-base-thai-ud-goeswith"
self.tokenizer: AutoTokenizer = AutoTokenizer.from_pretrained(model)
- self.model: AutoModelForTokenClassification = AutoModelForTokenClassification.from_pretrained(model)
+ self.model: AutoModelForTokenClassification = (
+ AutoModelForTokenClassification.from_pretrained(model)
+ )
def __call__(
self, text: str, tag: str = "str"
diff --git a/pythainlp/summarize/freq.py b/pythainlp/summarize/freq.py
index 1e491b7a4..503be9969 100644
--- a/pythainlp/summarize/freq.py
+++ b/pythainlp/summarize/freq.py
@@ -13,7 +13,7 @@
from pythainlp.corpus import thai_stopwords
from pythainlp.tokenize import sent_tokenize, word_tokenize
-_STOPWORDS = thai_stopwords()
+_STOPWORDS: frozenset[str] = thai_stopwords()
class FrequencySummarizer:
@@ -61,7 +61,9 @@ def summarize(
word_tokenized_sents = [
word_tokenize(sent, engine=tokenizer) for sent in sents
]
- self.__freq: "defaultdict[str, float]" = self.__compute_frequencies(word_tokenized_sents)
+ self.__freq: "defaultdict[str, float]" = self.__compute_frequencies(
+ word_tokenized_sents
+ )
ranking: defaultdict[int, float] = defaultdict(int)
for i, sent in enumerate(word_tokenized_sents):
diff --git a/pythainlp/summarize/mt5.py b/pythainlp/summarize/mt5.py
index 57101f5dd..c9bd91dc1 100644
--- a/pythainlp/summarize/mt5.py
+++ b/pythainlp/summarize/mt5.py
@@ -51,7 +51,9 @@ def __init__(
else:
model_name = pretrained_mt5_model_name
self.model_name: str = model_name
- self.model: MT5ForConditionalGeneration = MT5ForConditionalGeneration.from_pretrained(model_name) # type: ignore[assignment]
+ self.model: MT5ForConditionalGeneration = (
+ MT5ForConditionalGeneration.from_pretrained(model_name)
+ ) # type: ignore[assignment]
self.tokenizer: T5Tokenizer = T5Tokenizer.from_pretrained(model_name) # type: ignore[assignment]
self.num_beams: int = num_beams
self.no_repeat_ngram_size: int = no_repeat_ngram_size
diff --git a/pythainlp/tag/thai_nner.py b/pythainlp/tag/thai_nner.py
index 1e94c205f..f06a71a4d 100644
--- a/pythainlp/tag/thai_nner.py
+++ b/pythainlp/tag/thai_nner.py
@@ -6,6 +6,7 @@
This module provides a wrapper for the Thai-NNER library which implements
Nested Named Entity Recognition for Thai text.
"""
+
from __future__ import annotations
from typing import TYPE_CHECKING, Optional, Union
@@ -15,7 +16,7 @@
if TYPE_CHECKING:
from thai_nner import NNER
-__all__ = ["ThaiNNER"]
+__all__: list[str] = ["ThaiNNER"]
def _is_contained_in(entity: dict, container: dict) -> bool:
@@ -26,13 +27,16 @@ def _is_contained_in(entity: dict, container: dict) -> bool:
:return: True if entity is strictly contained in container
:rtype: bool
"""
- ent_start, ent_end = entity['span']
- cont_start, cont_end = container['span']
+ ent_start, ent_end = entity["span"]
+ cont_start, cont_end = container["span"]
# Entity is contained if its span is within or equal to container's span,
# but they're not exactly the same entity
- return (cont_start <= ent_start and cont_end >= ent_end and
- not (cont_start == ent_start and cont_end == ent_end))
+ return (
+ cont_start <= ent_start
+ and cont_end >= ent_end
+ and not (cont_start == ent_start and cont_end == ent_end)
+ )
def get_top_level_entities(entities: list[dict]) -> list[dict]:
@@ -54,9 +58,9 @@ def get_top_level_entities(entities: list[dict]) -> list[dict]:
# Input: nested entities where 'time' contains 'cardinal' and 'unit'
entities = [
- {'text': ['ห้า'], 'span': [7, 9], 'entity_type': 'cardinal'},
- {'text': ['ห้า', 'โมง'], 'span': [7, 11], 'entity_type': 'time'},
- {'text': ['โมง'], 'span': [9, 11], 'entity_type': 'unit'}
+ {"text": ["ห้า"], "span": [7, 9], "entity_type": "cardinal"},
+ {"text": ["ห้า", "โมง"], "span": [7, 11], "entity_type": "time"},
+ {"text": ["โมง"], "span": [9, 11], "entity_type": "unit"},
]
# Output: only 'time' entity (the outermost one)
@@ -68,7 +72,9 @@ def get_top_level_entities(entities: list[dict]) -> list[dict]:
# Sort entities by span start, then by span end (descending)
# This helps us process larger spans first
- sorted_entities = sorted(entities, key=lambda x: (x['span'][0], -x['span'][1]))
+ sorted_entities = sorted(
+ entities, key=lambda x: (x["span"][0], -x["span"][1])
+ )
top_level = []
for ent in sorted_entities:
@@ -128,7 +134,9 @@ def __init__(self, path_model: Optional[str] = None) -> None:
)
self.model: NNER = NNER(path_model=path_model)
- def tag(self, text: str, top_level_only: bool = False) -> tuple[list[str], list[dict]]:
+ def tag(
+ self, text: str, top_level_only: bool = False
+ ) -> tuple[list[str], list[dict]]:
"""Tag Thai text with nested named entities.
:param str text: Thai text to tag
@@ -151,14 +159,18 @@ def tag(self, text: str, top_level_only: bool = False) -> tuple[list[str], list[
tokens, entities = nner.tag("วันที่ 5 เมษายน 2565")
# Get only top-level entities
- tokens, top_entities = nner.tag("วันที่ 5 เมษายน 2565", top_level_only=True)
+ tokens, top_entities = nner.tag(
+ "วันที่ 5 เมษายน 2565", top_level_only=True
+ )
"""
tokens, entities = self.model.get_tag(text)
if top_level_only:
entities = get_top_level_entities(entities)
return tokens, entities
- def get_ner(self, text: str, pos: bool = False, tag: bool = False) -> Union[list[tuple[str, str]], str]:
+ def get_ner(
+ self, text: str, pos: bool = False, tag: bool = False
+ ) -> Union[list[tuple[str, str]], str]:
"""Tag Thai text with named entities in IOB format.
This method provides compatibility with the NER class interface by
@@ -202,7 +214,9 @@ def get_ner(self, text: str, pos: bool = False, tag: bool = False) -> Union[list
return _entities_to_iob(tokens, entities)
-def _entities_to_iob(tokens: list[str], entities: list[dict]) -> list[tuple[str, str]]:
+def _entities_to_iob(
+ tokens: list[str], entities: list[dict]
+) -> list[tuple[str, str]]:
"""Convert Thai-NNER entity format to IOB format.
This function assumes entities do not overlap. When converting nested
@@ -216,20 +230,20 @@ def _entities_to_iob(tokens: list[str], entities: list[dict]) -> list[tuple[str,
:rtype: list[tuple[str, str]]
"""
# Initialize all tokens as 'O' (outside)
- iob_tags = ['O'] * len(tokens)
+ iob_tags = ["O"] * len(tokens)
# Process each entity
for entity in entities:
- start, end = entity['span']
- entity_type = entity['entity_type'].upper()
+ start, end = entity["span"]
+ entity_type = entity["entity_type"].upper()
# Tag the first token as B- (beginning)
if start < len(iob_tags):
- iob_tags[start] = f'B-{entity_type}'
+ iob_tags[start] = f"B-{entity_type}"
# Tag subsequent tokens as I- (inside)
for i in range(start + 1, min(end, len(iob_tags))):
- iob_tags[i] = f'I-{entity_type}'
+ iob_tags[i] = f"I-{entity_type}"
# Combine tokens with their tags
result = [(token, tag) for token, tag in zip(tokens, iob_tags)]
@@ -249,26 +263,26 @@ def _entities_to_html(tokens: list[str], entities: list[dict]) -> str:
:rtype: str
"""
# Sort entities by start position to process in order
- sorted_entities = sorted(entities, key=lambda x: x['span'][0])
+ sorted_entities = sorted(entities, key=lambda x: x["span"][0])
# Build the result string
result_parts = []
last_pos = 0
for entity in sorted_entities:
- start, end = entity['span']
- entity_type = entity['entity_type'].upper()
+ start, end = entity["span"]
+ entity_type = entity["entity_type"].upper()
# Add tokens before this entity
result_parts.extend(tokens[last_pos:start])
# Add entity with tags
- entity_text = ''.join(tokens[start:end])
- result_parts.append(f'<{entity_type}>{entity_text}{entity_type}>')
+ entity_text = "".join(tokens[start:end])
+ result_parts.append(f"<{entity_type}>{entity_text}{entity_type}>")
last_pos = end
# Add remaining tokens
result_parts.extend(tokens[last_pos:])
- return ''.join(result_parts)
+ return "".join(result_parts)
diff --git a/pythainlp/tag/thainer.py b/pythainlp/tag/thainer.py
index 38a2391c9..012b88a36 100644
--- a/pythainlp/tag/thainer.py
+++ b/pythainlp/tag/thainer.py
@@ -5,7 +5,7 @@
from __future__ import annotations
-__all__ = ["ThaiNameTagger"]
+__all__: list[str] = ["ThaiNameTagger"]
from typing import TYPE_CHECKING, Union
@@ -18,7 +18,7 @@
if TYPE_CHECKING:
from pycrfsuite import Tagger as CRFTagger
-_TOKENIZER_ENGINE = "mm"
+_TOKENIZER_ENGINE: str = "mm"
def _is_stopword(word: str) -> bool: # เช็คว่าเป็นคำฟุ่มเฟือย
diff --git a/pythainlp/tokenize/pyicu.py b/pythainlp/tokenize/pyicu.py
index 4752ec196..fd9ca714a 100644
--- a/pythainlp/tokenize/pyicu.py
+++ b/pythainlp/tokenize/pyicu.py
@@ -18,7 +18,7 @@
from icu import BreakIterator, Locale
# Thread-local storage for BreakIterator instances
-_thread_local = threading.local()
+_thread_local: threading.local = threading.local()
def _get_break_iterator() -> BreakIterator:
diff --git a/pythainlp/transliterate/pyicu.py b/pythainlp/transliterate/pyicu.py
index 2efc5576f..0c6bf6af6 100644
--- a/pythainlp/transliterate/pyicu.py
+++ b/pythainlp/transliterate/pyicu.py
@@ -13,7 +13,9 @@
from icu import Transliterator
-_ICU_THAI_TO_LATIN = Transliterator.createInstance("Thai-Latin")
+_ICU_THAI_TO_LATIN: Transliterator = Transliterator.createInstance(
+ "Thai-Latin"
+)
def transliterate(text: str) -> str:
From 3ef033e7fedbb4545ea4590f85a120b398135607 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 4 Feb 2026 08:44:53 +0000
Subject: [PATCH 06/17] Fix problematic top-level imports of optional
dependencies
Moved numpy, torch, pandas, and other optional dependency imports from module level to:
- TYPE_CHECKING blocks (for type annotations only)
- Inside functions/methods where they're actually used
This prevents ImportError when users don't have these optional dependencies installed.
Fixed files:
- benchmarks/word_tokenization.py: numpy, pandas
- classify/param_free.py: numpy
- parse/ud_goeswith.py: numpy, torch
- tag/wangchanberta_onnx.py: numpy
- transliterate/thai2rom_onnx.py: numpy
- transliterate/thaig2p.py: numpy, torch
- transliterate/w2p.py: numpy
- ulmfit/core.py: numpy
- chat/core.py: torch
Co-authored-by: bact <128572+bact@users.noreply.github.com>
---
pythainlp/benchmarks/word_tokenization.py | 21 ++++--
pythainlp/chat/core.py | 12 +++-
pythainlp/classify/param_free.py | 14 ++--
pythainlp/parse/ud_goeswith.py | 2 +-
pythainlp/tag/wangchanberta_onnx.py | 13 ++--
pythainlp/transliterate/thai2rom_onnx.py | 24 +++++--
pythainlp/transliterate/thaig2p.py | 10 ++-
pythainlp/transliterate/w2p.py | 82 ++++++++++++++++++-----
pythainlp/ulmfit/core.py | 10 ++-
9 files changed, 142 insertions(+), 46 deletions(-)
diff --git a/pythainlp/benchmarks/word_tokenization.py b/pythainlp/benchmarks/word_tokenization.py
index 8a58e6360..2ba01ef4c 100644
--- a/pythainlp/benchmarks/word_tokenization.py
+++ b/pythainlp/benchmarks/word_tokenization.py
@@ -5,10 +5,11 @@
import re
import sys
-from typing import Any
+from typing import TYPE_CHECKING, Any
-import numpy as np
-import pandas as pd
+if TYPE_CHECKING:
+ import numpy as np
+ import pandas as pd
SEPARATOR: str = "|"
@@ -64,7 +65,7 @@ def _flatten_result(my_dict: dict, sep: str = ":") -> dict[str, Any]:
}
-def benchmark(ref_samples: list[str], samples: list[str]) -> pd.DataFrame:
+def benchmark(ref_samples: list[str], samples: list[str]) -> "pd.DataFrame":
"""Performance benchmarking for samples.
Please see :meth:`pythainlp.benchmarks.word_tokenization.compute_stats` for
@@ -76,6 +77,8 @@ def benchmark(ref_samples: list[str], samples: list[str]) -> pd.DataFrame:
:return: dataframe with row x col = len(samples) x len(metrics)
:rtype: pandas.DataFrame
"""
+ import pandas as pd
+
results = []
for i, (r, s) in enumerate(zip(ref_samples, samples)):
try:
@@ -149,6 +152,8 @@ def compute_stats(ref_sample: str, raw_sample: str) -> dict[str, Any]:
:return: metrics at character- and word-level and indicators of correctly tokenized words
:rtype: dict[str, Any]
"""
+ import numpy as np
+
ref_sample_arr = _binary_representation(ref_sample)
sample_arr = _binary_representation(raw_sample)
@@ -200,7 +205,7 @@ def compute_stats(ref_sample: str, raw_sample: str) -> dict[str, Any]:
}
-def _binary_representation(txt: str, verbose: bool = False) -> np.ndarray:
+def _binary_representation(txt: str, verbose: bool = False) -> "np.ndarray":
"""Transform text into {0, 1} sequence.
where (1) indicates that the corresponding character is the beginning of
@@ -212,6 +217,8 @@ def _binary_representation(txt: str, verbose: bool = False) -> np.ndarray:
:return: {0, 1} sequence
:rtype: np.ndarray
"""
+ import numpy as np
+
chars = np.array(list(txt))
boundary = np.argwhere(chars == SEPARATOR).reshape(-1)
@@ -236,7 +243,7 @@ def _binary_representation(txt: str, verbose: bool = False) -> np.ndarray:
return bin_rept
-def _find_word_boundaries(bin_reps: np.ndarray) -> list[tuple[int, int]]:
+def _find_word_boundaries(bin_reps: "np.ndarray") -> list[tuple[int, int]]:
"""Find the starting and ending location of each word.
:param str bin_reps: binary representation of a text
@@ -244,6 +251,8 @@ def _find_word_boundaries(bin_reps: np.ndarray) -> list[tuple[int, int]]:
:return: list of tuples (start, end)
:rtype: list[tuple[int, int]]
"""
+ import numpy as np
+
boundary = np.argwhere(bin_reps == 1).reshape(-1)
start_idx = boundary
end_idx = boundary[1:].tolist() + [bin_reps.shape[0]]
diff --git a/pythainlp/chat/core.py b/pythainlp/chat/core.py
index 4b4d24380..50712cf87 100644
--- a/pythainlp/chat/core.py
+++ b/pythainlp/chat/core.py
@@ -3,7 +3,10 @@
# SPDX-License-Identifier: Apache-2.0
from __future__ import annotations
-import torch
+from typing import TYPE_CHECKING
+
+if TYPE_CHECKING:
+ import torch
class ChatBotModel:
@@ -21,7 +24,7 @@ def load_model(
return_dict: bool = True,
load_in_8bit: bool = False,
device: str = "cuda",
- torch_dtype: torch.dtype = torch.float16,
+ torch_dtype: "torch.dtype | None" = None,
offload_folder: str = "./",
low_cpu_mem_usage: bool = True,
) -> None:
@@ -35,6 +38,11 @@ def load_model(
:param str offload_folder: offload folder
:param bool low_cpu_mem_usage: low cpu mem usage
"""
+ import torch
+
+ if torch_dtype is None:
+ torch_dtype = torch.float16
+
if model_name == "wangchanglm":
from pythainlp.generate.wangchanglm import WangChanGLM
diff --git a/pythainlp/classify/param_free.py b/pythainlp/classify/param_free.py
index c9cf1b91d..e94b65ef0 100644
--- a/pythainlp/classify/param_free.py
+++ b/pythainlp/classify/param_free.py
@@ -5,10 +5,10 @@
import gzip
import json
-from typing import Any, Optional
+from typing import TYPE_CHECKING, Any, Optional
-import numpy as np
-from numpy.typing import NDArray
+if TYPE_CHECKING:
+ from numpy.typing import NDArray
class GzipModel:
@@ -22,14 +22,16 @@ class GzipModel:
Default is empty string.
"""
-
cx2_list: list[int]
training_data: "NDArray[Any]"
+
def __init__(
self,
training_data: Optional[list[tuple[str, str]]] = None,
model_path: str = "",
) -> None:
+ import numpy as np
+
if model_path:
self.load(model_path)
else:
@@ -72,6 +74,8 @@ def predict(self, x1: str, k: int = 1) -> str:
print(model.predict("ฉันดีใจ", k=1))
# output: Positive
"""
+ import numpy as np
+
cx1 = len(gzip.compress(x1.encode("utf-8")))
disance_from_x1 = []
for i in range(len(self.cx2_list)):
@@ -104,6 +108,8 @@ def save(self, path: str) -> None:
def load(self, path: str) -> None:
""":param str path: path to load model"""
+ import numpy as np
+
with open(path, "r", encoding="utf-8") as f:
data = json.load(f)
self.cx2_list = data["cx2_list"]
diff --git a/pythainlp/parse/ud_goeswith.py b/pythainlp/parse/ud_goeswith.py
index 58a10bfb8..04a821d5f 100644
--- a/pythainlp/parse/ud_goeswith.py
+++ b/pythainlp/parse/ud_goeswith.py
@@ -13,7 +13,6 @@
from typing import TYPE_CHECKING, List, Optional, Union
-import numpy as np
import torch
from transformers import AutoModelForTokenClassification, AutoTokenizer
@@ -36,6 +35,7 @@ def __init__(
def __call__(
self, text: str, tag: str = "str"
) -> Union[List[List[str]], str]:
+ import numpy as np
import ufal.chu_liu_edmonds
w = self.tokenizer(text, return_offsets_mapping=True)
diff --git a/pythainlp/tag/wangchanberta_onnx.py b/pythainlp/tag/wangchanberta_onnx.py
index eec491ea3..b09ae2619 100644
--- a/pythainlp/tag/wangchanberta_onnx.py
+++ b/pythainlp/tag/wangchanberta_onnx.py
@@ -4,9 +4,10 @@
from __future__ import annotations
import json
-from typing import Union
+from typing import TYPE_CHECKING, Union
-import numpy as np
+if TYPE_CHECKING:
+ import numpy as np
from pythainlp.corpus import get_path_folder_corpus
@@ -55,7 +56,9 @@ def __init__(
self._json = json.load(fh)
self.id2tag = self._json["id2label"]
- def build_tokenizer(self, sent: str) -> dict[str, np.ndarray]:
+ def build_tokenizer(self, sent: str) -> dict[str, "np.ndarray"]:
+ import numpy as np
+
_t = [5] + [i + 4 for i in self.sp.encode(sent)] + [6]
model_inputs = {}
model_inputs["input_ids"] = np.array([_t], dtype=np.int64)
@@ -64,7 +67,9 @@ def build_tokenizer(self, sent: str) -> dict[str, np.ndarray]:
)
return model_inputs
- def postprocess(self, logits_data: np.ndarray) -> np.ndarray:
+ def postprocess(self, logits_data: "np.ndarray") -> "np.ndarray":
+ import numpy as np
+
logits_t = logits_data[0]
maxes = np.max(logits_t, axis=-1, keepdims=True)
shifted_exp = np.exp(logits_t - maxes)
diff --git a/pythainlp/transliterate/thai2rom_onnx.py b/pythainlp/transliterate/thai2rom_onnx.py
index d255abc2e..c8f914c50 100644
--- a/pythainlp/transliterate/thai2rom_onnx.py
+++ b/pythainlp/transliterate/thai2rom_onnx.py
@@ -8,7 +8,6 @@
import json
from typing import TYPE_CHECKING
-import numpy as np
from onnxruntime import InferenceSession
from pythainlp.corpus import get_corpus_path
@@ -16,6 +15,8 @@
if TYPE_CHECKING:
from typing import Dict, List
+ import numpy as np
+
_MODEL_ENCODER_NAME = "thai2rom_encoder_onnx"
_MODEL_DECODER_NAME = "thai2rom_decoder_onnx"
_MODEL_CONFIG_NAME = "thai2rom_config_onnx"
@@ -47,9 +48,13 @@ def __init__(self) -> None:
# encoder/ decoder
# Load encoder decoder onnx models.
- self._encoder: InferenceSession = InferenceSession(self.__encoder_filename)
+ self._encoder: InferenceSession = InferenceSession(
+ self.__encoder_filename
+ )
- self._decoder: InferenceSession = InferenceSession(self.__decoder_filename)
+ self._decoder: InferenceSession = InferenceSession(
+ self.__decoder_filename
+ )
self._network: Seq2Seq_ONNX = Seq2Seq_ONNX(
self._encoder,
@@ -60,8 +65,10 @@ def __init__(self) -> None:
target_vocab_size=OUTPUT_DIM,
)
- def _prepare_sequence_in(self, text: str) -> np.ndarray:
+ def _prepare_sequence_in(self, text: str) -> "np.ndarray":
"""Prepare input sequence for ONNX"""
+ import numpy as np
+
idxs = []
for ch in text:
if ch in self._char_to_ix:
@@ -76,6 +83,8 @@ def romanize(self, text: str) -> str:
:return: English (more or less) text that spells out how the Thai text
should be pronounced.
"""
+ import numpy as np
+
input_tensor = self._prepare_sequence_in(text).reshape(1, -1)
input_length = [len(text) + 1]
target_tensor_logits = self._network.run(input_tensor, input_length)
@@ -112,14 +121,17 @@ def __init__(
self.target_vocab_size = target_vocab_size
- def create_mask(self, source_seq: np.ndarray) -> np.ndarray:
+ def create_mask(self, source_seq: "np.ndarray") -> "np.ndarray":
mask = source_seq != self.pad_idx
return mask
- def run(self, source_seq: np.ndarray, source_seq_len: List[int]) -> np.ndarray:
+ def run(
+ self, source_seq: "np.ndarray", source_seq_len: List[int]
+ ) -> "np.ndarray":
# source_seq: (batch_size, MAX_LENGTH)
# source_seq_len: (batch_size, 1)
# target_seq: (batch_size, MAX_LENGTH)
+ import numpy as np
batch_size = source_seq.shape[0]
start_token = self.target_start_token
diff --git a/pythainlp/transliterate/thaig2p.py b/pythainlp/transliterate/thaig2p.py
index 3b0f82458..ece6826c5 100644
--- a/pythainlp/transliterate/thaig2p.py
+++ b/pythainlp/transliterate/thaig2p.py
@@ -10,7 +10,6 @@
import random
from typing import TYPE_CHECKING, Optional, Union
-import numpy as np
import torch
import torch.nn.functional as F
from torch import nn
@@ -65,7 +64,9 @@ def __init__(self) -> None:
# encoder/ decoder
# Restore the model and construct the encoder and decoder.
- self._encoder: "Encoder" = Encoder(INPUT_DIM, E_EMB_DIM, E_HID_DIM, E_DROPOUT)
+ self._encoder: "Encoder" = Encoder(
+ INPUT_DIM, E_EMB_DIM, E_HID_DIM, E_DROPOUT
+ )
self._decoder: "AttentionDecoder" = AttentionDecoder(
OUTPUT_DIM, D_EMB_DIM, D_HID_DIM, D_DROPOUT
@@ -152,9 +153,12 @@ def forward(
) -> tuple[torch.Tensor, tuple[torch.Tensor, torch.Tensor]]:
# sequences: (batch_size, sequence_length=MAX_LENGTH)
# sequences_lengths: (batch_size)
+ import numpy as np
batch_size = sequences.size(0)
- self.hidden: tuple[torch.Tensor, torch.Tensor] = self.init_hidden(batch_size)
+ self.hidden: tuple[torch.Tensor, torch.Tensor] = self.init_hidden(
+ batch_size
+ )
sequences_lengths = np.sort(sequences_lengths)[::-1]
index_sorted = np.argsort(
diff --git a/pythainlp/transliterate/w2p.py b/pythainlp/transliterate/w2p.py
index e713a412d..3d703134c 100644
--- a/pythainlp/transliterate/w2p.py
+++ b/pythainlp/transliterate/w2p.py
@@ -9,11 +9,10 @@
from typing import TYPE_CHECKING, Optional
-import numpy as np
-
from pythainlp.corpus import download, get_corpus_path
if TYPE_CHECKING:
+ import numpy as np
from numpy.typing import NDArray
_GRAPHEMES = list(
@@ -41,7 +40,9 @@ class _Hparams:
hp = _Hparams()
-def _load_vocab() -> tuple[dict[str, int], dict[int, str], dict[str, int], dict[int, str]]:
+def _load_vocab() -> tuple[
+ dict[str, int], dict[int, str], dict[str, int], dict[int, str]
+]:
g2idx = {g: idx for idx, g in enumerate(hp.graphemes)}
idx2g = dict(enumerate(hp.graphemes))
@@ -83,7 +84,9 @@ def __init__(self) -> None:
self.p2idx: dict[str, int]
self.idx2p: dict[int, str]
self.g2idx, self.idx2g, self.p2idx, self.idx2p = _load_vocab()
- self.checkpoint: Optional[str] = get_corpus_path(_MODEL_NAME, version="0.2")
+ self.checkpoint: Optional[str] = get_corpus_path(
+ _MODEL_NAME, version="0.2"
+ )
if self.checkpoint is None:
download(_MODEL_NAME, version="0.2")
self.checkpoint = get_corpus_path(_MODEL_NAME)
@@ -94,39 +97,73 @@ def __init__(self) -> None:
self._load_variables()
def _load_variables(self) -> None:
+ import numpy as np
+
if self.checkpoint is None:
raise RuntimeError("checkpoint path is not set")
self.variables: "NDArray" = np.load(self.checkpoint, allow_pickle=True)
# (29, 64). (len(graphemes), emb)
- self.enc_emb: "NDArray" = self.variables.item().get("encoder.emb.weight")
+ self.enc_emb: "NDArray" = self.variables.item().get(
+ "encoder.emb.weight"
+ )
# (3*128, 64)
- self.enc_w_ih: "NDArray" = self.variables.item().get("encoder.rnn.weight_ih_l0")
+ self.enc_w_ih: "NDArray" = self.variables.item().get(
+ "encoder.rnn.weight_ih_l0"
+ )
# (3*128, 128)
- self.enc_w_hh: "NDArray" = self.variables.item().get("encoder.rnn.weight_hh_l0")
+ self.enc_w_hh: "NDArray" = self.variables.item().get(
+ "encoder.rnn.weight_hh_l0"
+ )
# (3*128,)
- self.enc_b_ih: "NDArray" = self.variables.item().get("encoder.rnn.bias_ih_l0")
+ self.enc_b_ih: "NDArray" = self.variables.item().get(
+ "encoder.rnn.bias_ih_l0"
+ )
# (3*128,)
- self.enc_b_hh: "NDArray" = self.variables.item().get("encoder.rnn.bias_hh_l0")
+ self.enc_b_hh: "NDArray" = self.variables.item().get(
+ "encoder.rnn.bias_hh_l0"
+ )
# (74, 64). (len(phonemes), emb)
- self.dec_emb: "NDArray" = self.variables.item().get("decoder.emb.weight")
+ self.dec_emb: "NDArray" = self.variables.item().get(
+ "decoder.emb.weight"
+ )
# (3*128, 64)
- self.dec_w_ih: "NDArray" = self.variables.item().get("decoder.rnn.weight_ih_l0")
+ self.dec_w_ih: "NDArray" = self.variables.item().get(
+ "decoder.rnn.weight_ih_l0"
+ )
# (3*128, 128)
- self.dec_w_hh: "NDArray" = self.variables.item().get("decoder.rnn.weight_hh_l0")
+ self.dec_w_hh: "NDArray" = self.variables.item().get(
+ "decoder.rnn.weight_hh_l0"
+ )
# (3*128,)
- self.dec_b_ih: "NDArray" = self.variables.item().get("decoder.rnn.bias_ih_l0")
+ self.dec_b_ih: "NDArray" = self.variables.item().get(
+ "decoder.rnn.bias_ih_l0"
+ )
# (3*128,)
- self.dec_b_hh: "NDArray" = self.variables.item().get("decoder.rnn.bias_hh_l0")
+ self.dec_b_hh: "NDArray" = self.variables.item().get(
+ "decoder.rnn.bias_hh_l0"
+ )
# (74, 128)
self.fc_w: "NDArray" = self.variables.item().get("decoder.fc.weight")
# (74,)
self.fc_b: "NDArray" = self.variables.item().get("decoder.fc.bias")
- def _sigmoid(self, x: np.ndarray) -> np.ndarray:
+ def _sigmoid(self, x: "np.ndarray") -> "np.ndarray":
+ import numpy as np
+
return 1 / (1 + np.exp(-x))
- def _grucell(self, x: np.ndarray, h: np.ndarray, w_ih: np.ndarray, w_hh: np.ndarray, b_ih: np.ndarray, b_hh: np.ndarray) -> np.ndarray:
+ def _grucell(
+ self,
+ x: "np.ndarray",
+ h: "np.ndarray",
+ w_ih: "np.ndarray",
+ w_hh: "np.ndarray",
+ b_ih: "np.ndarray",
+ b_hh: "np.ndarray",
+ ) -> "np.ndarray":
+ import numpy as np
+
rzn_ih = np.matmul(x, w_ih.T) + b_ih
rzn_hh = np.matmul(h, w_hh.T) + b_hh
@@ -147,7 +184,18 @@ def _grucell(self, x: np.ndarray, h: np.ndarray, w_ih: np.ndarray, w_hh: np.ndar
return h
- def _gru(self, x: np.ndarray, steps: int, w_ih: np.ndarray, w_hh: np.ndarray, b_ih: np.ndarray, b_hh: np.ndarray, h0: Optional[np.ndarray] = None) -> np.ndarray:
+ def _gru(
+ self,
+ x: "np.ndarray",
+ steps: int,
+ w_ih: "np.ndarray",
+ w_hh: "np.ndarray",
+ b_ih: "np.ndarray",
+ b_hh: "np.ndarray",
+ h0: Optional["np.ndarray"] = None,
+ ) -> "np.ndarray":
+ import numpy as np
+
if h0 is None:
h0 = np.zeros((x.shape[0], w_hh.shape[1]), np.float32)
h = h0 # initial hidden state
diff --git a/pythainlp/ulmfit/core.py b/pythainlp/ulmfit/core.py
index 2e89c8b00..e5e61035e 100644
--- a/pythainlp/ulmfit/core.py
+++ b/pythainlp/ulmfit/core.py
@@ -7,11 +7,13 @@
import collections
from collections.abc import Callable, Collection
-from typing import Any, Optional
+from typing import TYPE_CHECKING, Any, Optional
-import numpy as np
import torch
+if TYPE_CHECKING:
+ import numpy as np
+
from pythainlp.corpus import get_corpus_path
from pythainlp.tokenize import thai2fit_tokenizer
from pythainlp.ulmfit.preprocess import (
@@ -174,7 +176,7 @@ def process_thai(
def document_vector(
text: str, learn: Any, data: Any, agg: str = "mean"
-) -> np.ndarray:
+) -> "np.ndarray":
"""This function vectorizes Thai input text into a 400 dimension vector using
:class:`fastai` language model and data bunch.
@@ -277,6 +279,8 @@ def merge_wgts(
)
# New embedding based on classification dataset
+ import numpy as np
+
new_w = np.zeros((vocab_size, em_sz), dtype=np.float32)
for i, w in enumerate(itos_new):
From 146f6e4ed7bfc16ff363f7d757acb8b5410d1c12 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 4 Feb 2026 08:46:13 +0000
Subject: [PATCH 07/17] Fix additional torch import issues in chat and generate
modules
Moved torch imports to TYPE_CHECKING and lazy loading in:
- chat/core.py: Fixed torch.dtype default parameter
- generate/wangchanglm.py: Moved torch to TYPE_CHECKING, added lazy import
Both files now use Optional torch_dtype with lazy default initialization.
Co-authored-by: bact <128572+bact@users.noreply.github.com>
---
pythainlp/generate/wangchanglm.py | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/pythainlp/generate/wangchanglm.py b/pythainlp/generate/wangchanglm.py
index 7f8df7d0f..82f237d9a 100644
--- a/pythainlp/generate/wangchanglm.py
+++ b/pythainlp/generate/wangchanglm.py
@@ -6,10 +6,9 @@
import re
from typing import TYPE_CHECKING
-import torch
-
if TYPE_CHECKING:
import pandas as pd
+ import torch
from transformers import PreTrainedModel, PreTrainedTokenizerBase
@@ -45,7 +44,7 @@ def load_model(
return_dict: bool = True,
load_in_8bit: bool = False,
device: str = "cuda",
- torch_dtype: torch.dtype = torch.float16,
+ torch_dtype: "torch.dtype | None" = None,
offload_folder: str = "./",
low_cpu_mem_usage: bool = True,
) -> None:
@@ -107,6 +106,8 @@ def gen_instruct(
:return: the answer from Instruct
:rtype: str
"""
+ import torch
+
batch = self.tokenizer(text, return_tensors="pt")
with torch.autocast(device_type=self.device, dtype=self.torch_dtype):
if thai_only:
From c56a5db5cf7007abc3cae6fb3484f699e1e75eb5 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 4 Feb 2026 08:48:45 +0000
Subject: [PATCH 08/17] Fix remaining torch import in parse/ud_goeswith.py
Moved top-level torch import to TYPE_CHECKING block and added lazy import in __call__ method.
Note: thaig2p.py and ulmfit/core.py still have torch imports but these are heavily torch-dependent modules where try/except pattern would be more appropriate for readability.
Co-authored-by: bact <128572+bact@users.noreply.github.com>
---
pythainlp/chat/core.py | 2 +-
pythainlp/generate/wangchanglm.py | 8 ++++++--
pythainlp/parse/ud_goeswith.py | 5 +++--
3 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/pythainlp/chat/core.py b/pythainlp/chat/core.py
index 50712cf87..d3a1967db 100644
--- a/pythainlp/chat/core.py
+++ b/pythainlp/chat/core.py
@@ -42,7 +42,7 @@ def load_model(
if torch_dtype is None:
torch_dtype = torch.float16
-
+
if model_name == "wangchanglm":
from pythainlp.generate.wangchanglm import WangChanGLM
diff --git a/pythainlp/generate/wangchanglm.py b/pythainlp/generate/wangchanglm.py
index 82f237d9a..4370034b2 100644
--- a/pythainlp/generate/wangchanglm.py
+++ b/pythainlp/generate/wangchanglm.py
@@ -73,12 +73,16 @@ def load_model(
offload_folder=offload_folder,
low_cpu_mem_usage=low_cpu_mem_usage,
)
- self.tokenizer: "PreTrainedTokenizerBase" = AutoTokenizer.from_pretrained(self.model_path)
+ self.tokenizer: "PreTrainedTokenizerBase" = (
+ AutoTokenizer.from_pretrained(self.model_path)
+ )
self.df: "pd.DataFrame" = pd.DataFrame(
self.tokenizer.vocab.items(), columns=["text", "idx"]
)
self.df["is_exclude"] = self.df.text.map(self.is_exclude)
- self.exclude_ids: list[int] = self.df[self.df.is_exclude is True].idx.tolist()
+ self.exclude_ids: list[int] = self.df[
+ self.df.is_exclude is True
+ ].idx.tolist()
def gen_instruct(
self,
diff --git a/pythainlp/parse/ud_goeswith.py b/pythainlp/parse/ud_goeswith.py
index 04a821d5f..836d889b7 100644
--- a/pythainlp/parse/ud_goeswith.py
+++ b/pythainlp/parse/ud_goeswith.py
@@ -13,11 +13,11 @@
from typing import TYPE_CHECKING, List, Optional, Union
-import torch
from transformers import AutoModelForTokenClassification, AutoTokenizer
if TYPE_CHECKING:
- pass
+ import numpy as np
+ import torch
class Parse:
@@ -36,6 +36,7 @@ def __call__(
self, text: str, tag: str = "str"
) -> Union[List[List[str]], str]:
import numpy as np
+ import torch
import ufal.chu_liu_edmonds
w = self.tokenizer(text, return_offsets_mapping=True)
From 7cc4925fc3271539248b99e150ec090dba27befc Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 4 Feb 2026 08:49:59 +0000
Subject: [PATCH 09/17] Add type annotations to module variables and fix
optional dependency imports
Co-authored-by: bact <128572+bact@users.noreply.github.com>
---
pythainlp/parse/ud_goeswith.py | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/pythainlp/parse/ud_goeswith.py b/pythainlp/parse/ud_goeswith.py
index 836d889b7..76826109f 100644
--- a/pythainlp/parse/ud_goeswith.py
+++ b/pythainlp/parse/ud_goeswith.py
@@ -16,8 +16,7 @@
from transformers import AutoModelForTokenClassification, AutoTokenizer
if TYPE_CHECKING:
- import numpy as np
- import torch
+ pass
class Parse:
From 0fe50cabfca59592a4c39c8189ccb1c8c8d117a3 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 4 Feb 2026 08:55:37 +0000
Subject: [PATCH 10/17] Fix Python 3.9 incompatible | union syntax in type
hints
Replace X | None with Optional[X] for Python 3.9 compatibility:
- chat/core.py: torch_dtype parameter
- generate/wangchanglm.py: torch_dtype parameter
- soundex/complete_soundex.py: _complete_soundex_instance
- corpus/core.py: _CHECK_MODE
- corpus/__init__.py: _CHECK_MODE (added Optional import)
- augment/word2vec/thai2fit.py: thai2fit_wv attribute
- augment/word2vec/ltw2v.py: ltw2v_wv attribute
The | union operator is only available in Python 3.10+. Since the project
requires Python 3.9+, all type hints must use Union[] or Optional[] syntax
for compatibility with introspection tools like typing.get_type_hints().
Co-authored-by: bact <128572+bact@users.noreply.github.com>
---
pythainlp/augment/word2vec/ltw2v.py | 4 ++--
pythainlp/augment/word2vec/thai2fit.py | 4 ++--
pythainlp/chat/core.py | 4 ++--
pythainlp/corpus/__init__.py | 3 ++-
pythainlp/corpus/core.py | 3 +--
pythainlp/generate/wangchanglm.py | 4 ++--
pythainlp/soundex/complete_soundex.py | 2 +-
7 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/pythainlp/augment/word2vec/ltw2v.py b/pythainlp/augment/word2vec/ltw2v.py
index bfa12a140..f7304575d 100644
--- a/pythainlp/augment/word2vec/ltw2v.py
+++ b/pythainlp/augment/word2vec/ltw2v.py
@@ -3,7 +3,7 @@
# SPDX-License-Identifier: Apache-2.0
from __future__ import annotations
-from typing import TYPE_CHECKING
+from typing import TYPE_CHECKING, Optional
if TYPE_CHECKING:
from pythainlp.augment.word2vec.core import Word2VecAug
@@ -23,7 +23,7 @@ class LTW2VAug:
`github.com/PyThaiNLP/large-thaiword2vec `_
"""
- ltw2v_wv: str | None
+ ltw2v_wv: Optional[str]
aug: Word2VecAug
def __init__(self) -> None:
diff --git a/pythainlp/augment/word2vec/thai2fit.py b/pythainlp/augment/word2vec/thai2fit.py
index 9c4ef0821..a0e5d83b6 100644
--- a/pythainlp/augment/word2vec/thai2fit.py
+++ b/pythainlp/augment/word2vec/thai2fit.py
@@ -3,7 +3,7 @@
# SPDX-License-Identifier: Apache-2.0
from __future__ import annotations
-from typing import TYPE_CHECKING
+from typing import TYPE_CHECKING, Optional
if TYPE_CHECKING:
from pythainlp.augment.word2vec.core import Word2VecAug
@@ -23,7 +23,7 @@ class Thai2fitAug:
`github.com/cstorm125/thai2fit `_
"""
- thai2fit_wv: str | None
+ thai2fit_wv: Optional[str]
aug: Word2VecAug
def __init__(self) -> None:
diff --git a/pythainlp/chat/core.py b/pythainlp/chat/core.py
index d3a1967db..50b0f6b75 100644
--- a/pythainlp/chat/core.py
+++ b/pythainlp/chat/core.py
@@ -3,7 +3,7 @@
# SPDX-License-Identifier: Apache-2.0
from __future__ import annotations
-from typing import TYPE_CHECKING
+from typing import TYPE_CHECKING, Optional
if TYPE_CHECKING:
import torch
@@ -24,7 +24,7 @@ def load_model(
return_dict: bool = True,
load_in_8bit: bool = False,
device: str = "cuda",
- torch_dtype: "torch.dtype | None" = None,
+ torch_dtype: Optional["torch.dtype"] = None,
offload_folder: str = "./",
low_cpu_mem_usage: bool = True,
) -> None:
diff --git a/pythainlp/corpus/__init__.py b/pythainlp/corpus/__init__.py
index 05f09b1fc..6681ee01b 100644
--- a/pythainlp/corpus/__init__.py
+++ b/pythainlp/corpus/__init__.py
@@ -47,6 +47,7 @@
]
import os
+from typing import Optional
from pythainlp.tools import get_full_data_path, get_pythainlp_path
@@ -54,7 +55,7 @@
_CORPUS_DIRNAME: str = "corpus"
_CORPUS_PATH: str = os.path.join(get_pythainlp_path(), _CORPUS_DIRNAME)
-_CHECK_MODE: str | None = os.getenv("PYTHAINLP_READ_MODE")
+_CHECK_MODE: Optional[str] = os.getenv("PYTHAINLP_READ_MODE")
# URL of remote corpus catalog
_CORPUS_DB_URL: str = "https://pythainlp.org/pythainlp-corpus/db.json"
diff --git a/pythainlp/corpus/core.py b/pythainlp/corpus/core.py
index a75533cd3..d774652c3 100644
--- a/pythainlp/corpus/core.py
+++ b/pythainlp/corpus/core.py
@@ -5,7 +5,6 @@
from __future__ import annotations
-import http.client
import json
import os
import re
@@ -23,7 +22,7 @@
if TYPE_CHECKING:
from typing import Any, Optional
-_CHECK_MODE: str | None = os.getenv("PYTHAINLP_READ_MODE")
+_CHECK_MODE: Optional[str] = os.getenv("PYTHAINLP_READ_MODE")
_USER_AGENT: str = (
f"PyThaiNLP/{__version__} "
f"(Python/{sys.version_info.major}.{sys.version_info.minor}; "
diff --git a/pythainlp/generate/wangchanglm.py b/pythainlp/generate/wangchanglm.py
index 4370034b2..a09880a2b 100644
--- a/pythainlp/generate/wangchanglm.py
+++ b/pythainlp/generate/wangchanglm.py
@@ -4,7 +4,7 @@
from __future__ import annotations
import re
-from typing import TYPE_CHECKING
+from typing import TYPE_CHECKING, Optional
if TYPE_CHECKING:
import pandas as pd
@@ -44,7 +44,7 @@ def load_model(
return_dict: bool = True,
load_in_8bit: bool = False,
device: str = "cuda",
- torch_dtype: "torch.dtype | None" = None,
+ torch_dtype: Optional["torch.dtype"] = None,
offload_folder: str = "./",
low_cpu_mem_usage: bool = True,
) -> None:
diff --git a/pythainlp/soundex/complete_soundex.py b/pythainlp/soundex/complete_soundex.py
index 1ccafd463..be5c196de 100644
--- a/pythainlp/soundex/complete_soundex.py
+++ b/pythainlp/soundex/complete_soundex.py
@@ -615,7 +615,7 @@ def encode(self, text: str) -> str:
# Singleton instance for module-level function
-_complete_soundex_instance: "CompleteSoundex | None" = None
+_complete_soundex_instance: "Optional[CompleteSoundex]" = None
def complete_soundex(text: str) -> str:
From d7f8503cd96387fce768be41e74d49206c18f193 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 4 Feb 2026 09:06:15 +0000
Subject: [PATCH 11/17] Fix missing numpy imports in w2p.py _encode and
_predict methods
Add missing 'import numpy as np' statements to _encode and _predict methods
that were causing NameError in compact test suite.
The error occurred when thai_word_tone_detector called pronunciate, which
internally used these methods that reference numpy arrays but didn't have
the import statement after we moved to lazy loading of optional dependencies.
Fixes test_thai_word_tone_detector in tests.compact.testc_util
Co-authored-by: bact <128572+bact@users.noreply.github.com>
---
pythainlp/transliterate/w2p.py | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/pythainlp/transliterate/w2p.py b/pythainlp/transliterate/w2p.py
index 3d703134c..f254ad9fc 100644
--- a/pythainlp/transliterate/w2p.py
+++ b/pythainlp/transliterate/w2p.py
@@ -207,7 +207,9 @@ def _gru(
return outputs
- def _encode(self, word: str) -> np.ndarray:
+ def _encode(self, word: str) -> "np.ndarray":
+ import numpy as np
+
chars = list(word) + [""]
x = [self.g2idx.get(char, self.g2idx[""]) for char in chars]
x = np.take(self.enc_emb, np.expand_dims(x, 0), axis=0)
@@ -223,6 +225,8 @@ def _short_word(self, word: str) -> Optional[str]:
return None
def _predict(self, word: str) -> str:
+ import numpy as np
+
short_word = self._short_word(word)
if short_word is not None:
return short_word
From 8cf75230a18600d1f343c6acfa571bc0657ed8c9 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 4 Feb 2026 09:25:07 +0000
Subject: [PATCH 12/17] Plan: Continue adding variable type hints to reach 100%
coverage
Co-authored-by: bact <128572+bact@users.noreply.github.com>
---
.../analysis/output/type_hint_analysis.json | 220 +++++++++---------
1 file changed, 110 insertions(+), 110 deletions(-)
diff --git a/build_tools/analysis/output/type_hint_analysis.json b/build_tools/analysis/output/type_hint_analysis.json
index 971bf481a..efcccd5bf 100644
--- a/build_tools/analysis/output/type_hint_analysis.json
+++ b/build_tools/analysis/output/type_hint_analysis.json
@@ -37,121 +37,121 @@
"complete": 2,
"incomplete": 0,
"none": 0,
- "mypy_errors": 26
+ "mypy_errors": 0
},
"augment": {
"complete": 29,
"incomplete": 0,
"none": 0,
- "mypy_errors": 33
+ "mypy_errors": 0
},
"benchmarks": {
"complete": 8,
"incomplete": 0,
"none": 0,
- "mypy_errors": 26
+ "mypy_errors": 0
},
"chat": {
"complete": 4,
"incomplete": 0,
"none": 0,
- "mypy_errors": 28
+ "mypy_errors": 0
},
"classify": {
"complete": 5,
"incomplete": 0,
"none": 0,
- "mypy_errors": 26
+ "mypy_errors": 0
},
"cli": {
"complete": 21,
"incomplete": 0,
"none": 0,
- "mypy_errors": 28
+ "mypy_errors": 0
},
"coref": {
"complete": 5,
"incomplete": 0,
"none": 0,
- "mypy_errors": 26
+ "mypy_errors": 0
},
"corpus": {
"complete": 70,
"incomplete": 0,
"none": 0,
- "mypy_errors": 26
+ "mypy_errors": 0
},
"el": {
"complete": 5,
"incomplete": 0,
"none": 0,
- "mypy_errors": 26
+ "mypy_errors": 0
},
"generate": {
"complete": 15,
"incomplete": 0,
"none": 0,
- "mypy_errors": 31
+ "mypy_errors": 0
},
"khavee": {
"complete": 9,
"incomplete": 0,
"none": 0,
- "mypy_errors": 26
+ "mypy_errors": 0
},
"lm": {
"complete": 2,
"incomplete": 0,
"none": 0,
- "mypy_errors": 26
+ "mypy_errors": 0
},
"morpheme": {
"complete": 2,
"incomplete": 0,
"none": 0,
- "mypy_errors": 26
+ "mypy_errors": 0
},
"parse": {
"complete": 9,
"incomplete": 0,
"none": 0,
- "mypy_errors": 28
+ "mypy_errors": 0
},
"phayathaibert": {
"complete": 19,
"incomplete": 0,
"none": 0,
- "mypy_errors": 26
+ "mypy_errors": 0
},
"soundex": {
"complete": 27,
"incomplete": 0,
"none": 0,
- "mypy_errors": 26
+ "mypy_errors": 0
},
"spell": {
"complete": 43,
"incomplete": 0,
"none": 0,
- "mypy_errors": 26
+ "mypy_errors": 0
},
"summarize": {
"complete": 17,
"incomplete": 0,
"none": 0,
- "mypy_errors": 31
+ "mypy_errors": 0
},
"tag": {
"complete": 73,
"incomplete": 0,
"none": 0,
- "mypy_errors": 28
+ "mypy_errors": 0
},
"tokenize": {
"complete": 73,
"incomplete": 0,
"none": 0,
- "mypy_errors": 26
+ "mypy_errors": 0
},
"tokenizeicu": {
"complete": 3,
@@ -163,19 +163,19 @@
"complete": 9,
"incomplete": 0,
"none": 0,
- "mypy_errors": 26
+ "mypy_errors": 0
},
"translate": {
"complete": 44,
"incomplete": 0,
"none": 0,
- "mypy_errors": 33
+ "mypy_errors": 0
},
"transliterate": {
"complete": 75,
"incomplete": 0,
"none": 0,
- "mypy_errors": 27
+ "mypy_errors": 0
},
"transliterateicu": {
"complete": 1,
@@ -187,31 +187,31 @@
"complete": 25,
"incomplete": 0,
"none": 0,
- "mypy_errors": 30
+ "mypy_errors": 0
},
"util": {
"complete": 109,
"incomplete": 0,
"none": 0,
- "mypy_errors": 26
+ "mypy_errors": 0
},
"wangchanberta": {
"complete": 9,
"incomplete": 0,
"none": 0,
- "mypy_errors": 26
+ "mypy_errors": 0
},
"word_vector": {
"complete": 7,
"incomplete": 0,
"none": 0,
- "mypy_errors": 33
+ "mypy_errors": 0
},
"wsd": {
"complete": 4,
"incomplete": 0,
"none": 0,
- "mypy_errors": 28
+ "mypy_errors": 0
}
},
"functions_no_hints": [],
@@ -441,42 +441,42 @@
"scope": "public",
"parent_class": "ChatBotModel",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/chat/core.py",
- "line": 16
+ "line": 19
},
{
"name": "pythainlp.chat.core.ChatBotModel.model",
"scope": "public",
"parent_class": "ChatBotModel",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/chat/core.py",
- "line": 41
+ "line": 49
},
{
"name": "pythainlp.classify.param_free.GzipModel.training_data",
"scope": "public",
"parent_class": "GzipModel",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/classify/param_free.py",
- "line": 36
+ "line": 38
},
{
"name": "pythainlp.classify.param_free.GzipModel.cx2_list",
"scope": "public",
"parent_class": "GzipModel",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/classify/param_free.py",
- "line": 37
+ "line": 39
},
{
"name": "pythainlp.classify.param_free.GzipModel.cx2_list",
"scope": "public",
"parent_class": "GzipModel",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/classify/param_free.py",
- "line": 109
+ "line": 115
},
{
"name": "pythainlp.classify.param_free.GzipModel.training_data",
"scope": "public",
"parent_class": "GzipModel",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/classify/param_free.py",
- "line": 110
+ "line": 116
},
{
"name": "pythainlp.cli.tag.SubAppBase.args",
@@ -511,21 +511,21 @@
"scope": "public",
"parent_class": "_ResponseWrapper",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/core.py",
- "line": 42
+ "line": 41
},
{
"name": "pythainlp.corpus.core._ResponseWrapper.headers",
"scope": "public",
"parent_class": "_ResponseWrapper",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/core.py",
- "line": 43
+ "line": 42
},
{
"name": "pythainlp.corpus.core._ResponseWrapper._content",
"scope": "private",
"parent_class": "_ResponseWrapper",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/core.py",
- "line": 44
+ "line": 43
},
{
"name": "pythainlp.el._multiel.MultiEL.model_name",
@@ -574,63 +574,63 @@
"scope": "public",
"parent_class": "FastTextEncoder",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/words_spelling_correction.py",
- "line": 68
+ "line": 70
},
{
"name": "pythainlp.spell.words_spelling_correction.FastTextEncoder.nn_model_path",
"scope": "public",
"parent_class": "FastTextEncoder",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/words_spelling_correction.py",
- "line": 69
+ "line": 71
},
{
"name": "pythainlp.spell.words_spelling_correction.FastTextEncoder.bucket",
"scope": "public",
"parent_class": "FastTextEncoder",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/words_spelling_correction.py",
- "line": 70
+ "line": 72
},
{
"name": "pythainlp.spell.words_spelling_correction.FastTextEncoder.nb_words",
"scope": "public",
"parent_class": "FastTextEncoder",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/words_spelling_correction.py",
- "line": 71
+ "line": 73
},
{
"name": "pythainlp.spell.words_spelling_correction.FastTextEncoder.minn",
"scope": "public",
"parent_class": "FastTextEncoder",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/words_spelling_correction.py",
- "line": 72
+ "line": 74
},
{
"name": "pythainlp.spell.words_spelling_correction.FastTextEncoder.maxn",
"scope": "public",
"parent_class": "FastTextEncoder",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/words_spelling_correction.py",
- "line": 73
+ "line": 75
},
{
"name": "pythainlp.spell.words_spelling_correction.FastTextEncoder.words_for_suggestion",
"scope": "public",
"parent_class": "FastTextEncoder",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/words_spelling_correction.py",
- "line": 77
+ "line": 79
},
{
"name": "pythainlp.spell.words_spelling_correction.FastTextEncoder.nn_session",
"scope": "public",
"parent_class": "FastTextEncoder",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/words_spelling_correction.py",
- "line": 78
+ "line": 80
},
{
"name": "pythainlp.spell.words_spelling_correction.Words_Spelling_Correction.list_word",
"scope": "public",
"parent_class": "Words_Spelling_Correction",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/words_spelling_correction.py",
- "line": 267
+ "line": 269
},
{
"name": "pythainlp.summarize.keybert.KeyBERT.ft_pipeline",
@@ -721,21 +721,21 @@
"scope": "private",
"parent_class": "WngchanBerta_ONNX",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/tag/wangchanberta_onnx.py",
- "line": 55
+ "line": 56
},
{
"name": "pythainlp.tag.wangchanberta_onnx.WngchanBerta_ONNX.id2tag",
"scope": "public",
"parent_class": "WngchanBerta_ONNX",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/tag/wangchanberta_onnx.py",
- "line": 56
+ "line": 57
},
{
"name": "pythainlp.tag.wangchanberta_onnx.WngchanBerta_ONNX._s",
"scope": "private",
"parent_class": "WngchanBerta_ONNX",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/tag/wangchanberta_onnx.py",
- "line": 101
+ "line": 106
},
{
"name": "pythainlp.tokenize.attacut.AttacutTokenizer._MODEL_NAME",
@@ -1337,189 +1337,189 @@
"scope": "public",
"parent_class": "Seq2Seq_ONNX",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom_onnx.py",
- "line": 106
+ "line": 115
},
{
"name": "pythainlp.transliterate.thai2rom_onnx.Seq2Seq_ONNX.decoder",
"scope": "public",
"parent_class": "Seq2Seq_ONNX",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom_onnx.py",
- "line": 107
+ "line": 116
},
{
"name": "pythainlp.transliterate.thai2rom_onnx.Seq2Seq_ONNX.pad_idx",
"scope": "public",
"parent_class": "Seq2Seq_ONNX",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom_onnx.py",
- "line": 108
+ "line": 117
},
{
"name": "pythainlp.transliterate.thai2rom_onnx.Seq2Seq_ONNX.target_start_token",
"scope": "public",
"parent_class": "Seq2Seq_ONNX",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom_onnx.py",
- "line": 109
+ "line": 118
},
{
"name": "pythainlp.transliterate.thai2rom_onnx.Seq2Seq_ONNX.target_end_token",
"scope": "public",
"parent_class": "Seq2Seq_ONNX",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom_onnx.py",
- "line": 110
+ "line": 119
},
{
"name": "pythainlp.transliterate.thai2rom_onnx.Seq2Seq_ONNX.max_length",
"scope": "public",
"parent_class": "Seq2Seq_ONNX",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom_onnx.py",
- "line": 111
+ "line": 120
},
{
"name": "pythainlp.transliterate.thai2rom_onnx.Seq2Seq_ONNX.target_vocab_size",
"scope": "public",
"parent_class": "Seq2Seq_ONNX",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom_onnx.py",
- "line": 113
+ "line": 122
},
{
"name": "pythainlp.transliterate.thaig2p.Encoder.hidden_size",
"scope": "public",
"parent_class": "Encoder",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py",
- "line": 135
+ "line": 136
},
{
"name": "pythainlp.transliterate.thaig2p.Encoder.character_embedding",
"scope": "public",
"parent_class": "Encoder",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py",
- "line": 136
+ "line": 137
},
{
"name": "pythainlp.transliterate.thaig2p.Encoder.rnn",
"scope": "public",
"parent_class": "Encoder",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py",
- "line": 139
+ "line": 140
},
{
"name": "pythainlp.transliterate.thaig2p.Encoder.dropout",
"scope": "public",
"parent_class": "Encoder",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py",
- "line": 146
+ "line": 147
},
{
"name": "pythainlp.transliterate.thaig2p.Attn.method",
"scope": "public",
"parent_class": "Attn",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py",
- "line": 205
+ "line": 209
},
{
"name": "pythainlp.transliterate.thaig2p.Attn.hidden_size",
"scope": "public",
"parent_class": "Attn",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py",
- "line": 206
+ "line": 210
},
{
"name": "pythainlp.transliterate.thaig2p.Attn.attn",
"scope": "public",
"parent_class": "Attn",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py",
- "line": 212
+ "line": 216
},
{
"name": "pythainlp.transliterate.thaig2p.AttentionDecoder.vocabulary_size",
"scope": "public",
"parent_class": "AttentionDecoder",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py",
- "line": 264
+ "line": 268
},
{
"name": "pythainlp.transliterate.thaig2p.AttentionDecoder.hidden_size",
"scope": "public",
"parent_class": "AttentionDecoder",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py",
- "line": 265
+ "line": 269
},
{
"name": "pythainlp.transliterate.thaig2p.AttentionDecoder.character_embedding",
"scope": "public",
"parent_class": "AttentionDecoder",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py",
- "line": 266
+ "line": 270
},
{
"name": "pythainlp.transliterate.thaig2p.AttentionDecoder.rnn",
"scope": "public",
"parent_class": "AttentionDecoder",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py",
- "line": 269
+ "line": 273
},
{
"name": "pythainlp.transliterate.thaig2p.AttentionDecoder.attn",
"scope": "public",
"parent_class": "AttentionDecoder",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py",
- "line": 276
+ "line": 280
},
{
"name": "pythainlp.transliterate.thaig2p.AttentionDecoder.linear",
"scope": "public",
"parent_class": "AttentionDecoder",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py",
- "line": 277
+ "line": 281
},
{
"name": "pythainlp.transliterate.thaig2p.AttentionDecoder.dropout",
"scope": "public",
"parent_class": "AttentionDecoder",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py",
- "line": 279
+ "line": 283
},
{
"name": "pythainlp.transliterate.thaig2p.Seq2Seq.encoder",
"scope": "public",
"parent_class": "Seq2Seq",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py",
- "line": 325
+ "line": 329
},
{
"name": "pythainlp.transliterate.thaig2p.Seq2Seq.decoder",
"scope": "public",
"parent_class": "Seq2Seq",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py",
- "line": 326
+ "line": 330
},
{
"name": "pythainlp.transliterate.thaig2p.Seq2Seq.pad_idx",
"scope": "public",
"parent_class": "Seq2Seq",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py",
- "line": 327
+ "line": 331
},
{
"name": "pythainlp.transliterate.thaig2p.Seq2Seq.target_start_token",
"scope": "public",
"parent_class": "Seq2Seq",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py",
- "line": 328
+ "line": 332
},
{
"name": "pythainlp.transliterate.thaig2p.Seq2Seq.target_end_token",
"scope": "public",
"parent_class": "Seq2Seq",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py",
- "line": 329
+ "line": 333
},
{
"name": "pythainlp.transliterate.thaig2p.Seq2Seq.max_length",
"scope": "public",
"parent_class": "Seq2Seq",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py",
- "line": 330
+ "line": 334
},
{
"name": "pythainlp.transliterate.umt5_thaig2p.Umt5ThaiG2P.pipe",
@@ -1533,21 +1533,21 @@
"scope": "public",
"parent_class": "Thai_W2P",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/w2p.py",
- "line": 89
+ "line": 92
},
{
"name": "pythainlp.transliterate.w2p.Thai_W2P.word",
"scope": "public",
"parent_class": "Thai_W2P",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/w2p.py",
- "line": 172
+ "line": 222
},
{
"name": "pythainlp.transliterate.w2p.Thai_W2P.word",
"scope": "public",
"parent_class": "Thai_W2P",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/w2p.py",
- "line": 173
+ "line": 223
},
{
"name": "pythainlp.transliterate.wunsen.WunsenTransliterate.jp_input",
@@ -1645,21 +1645,21 @@
"scope": "public",
"parent_class": "ThaiNameTagger",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/wangchanberta/core.py",
- "line": 112
+ "line": 116
},
{
"name": "pythainlp.wangchanberta.core.ThaiNameTagger.sent_ner",
"scope": "public",
"parent_class": "ThaiNameTagger",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/wangchanberta/core.py",
- "line": 118
+ "line": 122
},
{
"name": "pythainlp.wangchanberta.core.ThaiNameTagger.sent_ner",
"scope": "public",
"parent_class": "ThaiNameTagger",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/wangchanberta/core.py",
- "line": 126
+ "line": 130
},
{
"name": "pythainlp.word_vector.core.WordVector.tokenize",
@@ -1977,7 +1977,7 @@
"name": "pythainlp.spell.words_spelling_correction._WSC",
"scope": "private",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/words_spelling_correction.py",
- "line": 271
+ "line": 273
},
{
"name": "pythainlp.tokenize._utils._DIGITS_WITH_SEPARATOR",
@@ -2403,43 +2403,43 @@
"name": "pythainlp.transliterate.thai2rom_onnx._MODEL_ENCODER_NAME",
"scope": "private",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom_onnx.py",
- "line": 19
+ "line": 20
},
{
"name": "pythainlp.transliterate.thai2rom_onnx._MODEL_DECODER_NAME",
"scope": "private",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom_onnx.py",
- "line": 20
+ "line": 21
},
{
"name": "pythainlp.transliterate.thai2rom_onnx._MODEL_CONFIG_NAME",
"scope": "private",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom_onnx.py",
- "line": 21
+ "line": 22
},
{
"name": "pythainlp.transliterate.thai2rom_onnx._THAI_TO_ROM_ONNX",
"scope": "private",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thai2rom_onnx.py",
- "line": 184
+ "line": 196
},
{
"name": "pythainlp.transliterate.thaig2p.device",
"scope": "public",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py",
- "line": 23
+ "line": 22
},
{
"name": "pythainlp.transliterate.thaig2p._MODEL_NAME",
"scope": "private",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py",
- "line": 25
+ "line": 24
},
{
"name": "pythainlp.transliterate.thaig2p._THAI_G2P",
"scope": "private",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/thaig2p.py",
- "line": 413
+ "line": 417
},
{
"name": "pythainlp.transliterate.thaig2p_v2._THAI_G2P",
@@ -2457,79 +2457,79 @@
"name": "pythainlp.transliterate.w2p._GRAPHEMES",
"scope": "private",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/w2p.py",
- "line": 19
+ "line": 18
},
{
"name": "pythainlp.transliterate.w2p._PHONEMES",
"scope": "private",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/w2p.py",
- "line": 22
+ "line": 21
},
{
"name": "pythainlp.transliterate.w2p._MODEL_NAME",
"scope": "private",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/w2p.py",
- "line": 26
+ "line": 25
},
{
"name": "pythainlp.transliterate.w2p.hp",
"scope": "public",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/w2p.py",
- "line": 41
+ "line": 40
},
{
"name": "pythainlp.transliterate.w2p._THAI_W2P",
"scope": "private",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/transliterate/w2p.py",
- "line": 229
+ "line": 281
},
{
"name": "pythainlp.ulmfit.core.device",
"scope": "public",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/ulmfit/core.py",
- "line": 34
+ "line": 36
},
{
"name": "pythainlp.ulmfit.core._MODEL_NAME_LSTM",
"scope": "private",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/ulmfit/core.py",
- "line": 36
+ "line": 38
},
{
"name": "pythainlp.ulmfit.core._ITOS_NAME_LSTM",
"scope": "private",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/ulmfit/core.py",
- "line": 37
+ "line": 39
},
{
"name": "pythainlp.ulmfit.core.THWIKI_LSTM",
"scope": "public",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/ulmfit/core.py",
- "line": 44
+ "line": 46
},
{
"name": "pythainlp.ulmfit.core.pre_rules_th",
"scope": "public",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/ulmfit/core.py",
- "line": 76
+ "line": 78
},
{
"name": "pythainlp.ulmfit.core.post_rules_th",
"scope": "public",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/ulmfit/core.py",
- "line": 86
+ "line": 88
},
{
"name": "pythainlp.ulmfit.core.pre_rules_th_sparse",
"scope": "public",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/ulmfit/core.py",
- "line": 89
+ "line": 91
},
{
"name": "pythainlp.ulmfit.core.post_rules_th_sparse",
"scope": "public",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/ulmfit/core.py",
- "line": 90
+ "line": 92
},
{
"name": "pythainlp.ulmfit.preprocess._TK_UNK",
@@ -2661,25 +2661,25 @@
"name": "pythainlp.util.emojiconv._th_emoji",
"scope": "private",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/util/emojiconv.py",
- "line": 1829
+ "line": 1828
},
{
"name": "pythainlp.util.emojiconv._emojis",
"scope": "private",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/util/emojiconv.py",
- "line": 1831
+ "line": 1830
},
{
"name": "pythainlp.util.emojiconv._emoji_regex",
"scope": "private",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/util/emojiconv.py",
- "line": 1832
+ "line": 1831
},
{
"name": "pythainlp.util.emojiconv._delimiter",
"scope": "private",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/util/emojiconv.py",
- "line": 1833
+ "line": 1832
},
{
"name": "pythainlp.util.keyboard.EN_TH_KEYB_PAIRS",
@@ -2925,7 +2925,7 @@
"name": "pythainlp.util.syllable.unknown",
"scope": "public",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/util/syllable.py",
- "line": 61
+ "line": 60
},
{
"name": "pythainlp.util.thai_lunar_date._BEGIN_DATES",
@@ -2985,13 +2985,13 @@
"name": "pythainlp.wangchanberta.core._model_name",
"scope": "private",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/wangchanberta/core.py",
- "line": 16
+ "line": 20
},
{
"name": "pythainlp.wangchanberta.core._tokenizer",
"scope": "private",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/wangchanberta/core.py",
- "line": 17
+ "line": 21
},
{
"name": "pythainlp.wsd.core.unknown",
From b11087c327fd313e4b2f6c4676127e951d0ccd9a Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 4 Feb 2026 09:30:29 +0000
Subject: [PATCH 13/17] Add type hints to module variables in corpus, generate,
spell, phayathaibert
Added type annotations to module-level variables in:
- corpus: tnc.py, ttc.py, volubilis.py, wikipedia.py
- coref/core.py: _MODEL
- generate: __init__.py, thai2fit.py (fastai types)
- spell: phunspell.py, symspellpy.py, wanchanberta_thai_grammarly.py
- phayathaibert: __init__.py, core.py
Progress: ~70 module variables annotated (from ~227 remaining)
Co-authored-by: bact <128572+bact@users.noreply.github.com>
---
pythainlp/coref/core.py | 4 +-
pythainlp/corpus/tnc.py | 8 ++--
pythainlp/corpus/ttc.py | 4 +-
pythainlp/corpus/volubilis.py | 6 ++-
pythainlp/corpus/wikipedia.py | 6 ++-
pythainlp/generate/__init__.py | 2 +-
pythainlp/generate/thai2fit.py | 41 +++++++++++++------
pythainlp/phayathaibert/__init__.py | 2 +-
pythainlp/phayathaibert/core.py | 27 ++++++++----
pythainlp/spell/phunspell.py | 7 +++-
pythainlp/spell/symspellpy.py | 14 ++++---
.../spell/wanchanberta_thai_grammarly.py | 20 +++++----
12 files changed, 91 insertions(+), 50 deletions(-)
diff --git a/pythainlp/coref/core.py b/pythainlp/coref/core.py
index 46e7aac1a..74726eec6 100644
--- a/pythainlp/coref/core.py
+++ b/pythainlp/coref/core.py
@@ -3,9 +3,9 @@
# SPDX-License-Identifier: Apache-2.0
from __future__ import annotations
-from typing import Union
+from typing import Any, Optional
-_MODEL = None
+_MODEL: Optional[Any] = None
def coreference_resolution(
diff --git a/pythainlp/corpus/tnc.py b/pythainlp/corpus/tnc.py
index 56c8836be..77ea39014 100644
--- a/pythainlp/corpus/tnc.py
+++ b/pythainlp/corpus/tnc.py
@@ -5,7 +5,7 @@
from __future__ import annotations
-__all__ = [
+__all__: list[str] = [
"bigram_word_freqs",
"trigram_word_freqs",
"unigram_word_freqs",
@@ -16,9 +16,9 @@
from pythainlp.corpus import get_corpus, get_corpus_path
-_UNIGRAM_FILENAME = "tnc_freq.txt"
-_BIGRAM_CORPUS_NAME = "tnc_bigram_word_freqs"
-_TRIGRAM_CORPUS_NAME = "tnc_trigram_word_freqs"
+_UNIGRAM_FILENAME: str = "tnc_freq.txt"
+_BIGRAM_CORPUS_NAME: str = "tnc_bigram_word_freqs"
+_TRIGRAM_CORPUS_NAME: str = "tnc_trigram_word_freqs"
def word_freqs() -> list[tuple[str, int]]:
diff --git a/pythainlp/corpus/ttc.py b/pythainlp/corpus/ttc.py
index 81c3c244b..9d3d0c8c8 100644
--- a/pythainlp/corpus/ttc.py
+++ b/pythainlp/corpus/ttc.py
@@ -9,13 +9,13 @@
from __future__ import annotations
-__all__ = ["word_freqs", "unigram_word_freqs"]
+__all__: list[str] = ["word_freqs", "unigram_word_freqs"]
from collections import defaultdict
from pythainlp.corpus import get_corpus
-_UNIGRAM_FILENAME = "ttc_freq.txt"
+_UNIGRAM_FILENAME: str = "ttc_freq.txt"
def word_freqs() -> list[tuple[str, int]]:
diff --git a/pythainlp/corpus/volubilis.py b/pythainlp/corpus/volubilis.py
index ed8993f3f..15e3bfdb0 100644
--- a/pythainlp/corpus/volubilis.py
+++ b/pythainlp/corpus/volubilis.py
@@ -5,10 +5,12 @@
from __future__ import annotations
+from typing import Optional
+
from pythainlp.corpus.core import get_corpus
-_VOLUBILIS_WORDS = None
-_VOLUBILIS_FILENAME = "volubilis_words_th.txt"
+_VOLUBILIS_WORDS: Optional[frozenset[str]] = None
+_VOLUBILIS_FILENAME: str = "volubilis_words_th.txt"
def thai_volubilis_words() -> frozenset[str]:
diff --git a/pythainlp/corpus/wikipedia.py b/pythainlp/corpus/wikipedia.py
index e1d8e6f6c..a746ee3e4 100644
--- a/pythainlp/corpus/wikipedia.py
+++ b/pythainlp/corpus/wikipedia.py
@@ -5,10 +5,12 @@
from __future__ import annotations
+from typing import Optional
+
from pythainlp.corpus.core import get_corpus
-_WIKIPEDIA_TITLES = None
-_WIKIPEDIA_TITLES_FILENAME = "wikipedia_titles_th.txt"
+_WIKIPEDIA_TITLES: Optional[frozenset[str]] = None
+_WIKIPEDIA_TITLES_FILENAME: str = "wikipedia_titles_th.txt"
def thai_wikipedia_titles() -> frozenset[str]:
diff --git a/pythainlp/generate/__init__.py b/pythainlp/generate/__init__.py
index 4bd86f306..50b018e4a 100644
--- a/pythainlp/generate/__init__.py
+++ b/pythainlp/generate/__init__.py
@@ -3,6 +3,6 @@
# SPDX-License-Identifier: Apache-2.0
"""Thai Text Generation"""
-__all__ = ["Bigram", "Trigram", "Unigram"]
+__all__: list[str] = ["Bigram", "Trigram", "Unigram"]
from pythainlp.generate.core import Bigram, Trigram, Unigram
diff --git a/pythainlp/generate/thai2fit.py b/pythainlp/generate/thai2fit.py
index 3f93c9090..f328c94b5 100644
--- a/pythainlp/generate/thai2fit.py
+++ b/pythainlp/generate/thai2fit.py
@@ -9,11 +9,21 @@
from __future__ import annotations
-__all__ = ["gen_sentence"]
+__all__: list[str] = ["gen_sentence"]
import pickle
import random
-from typing import Union
+from typing import TYPE_CHECKING, Any, Union
+
+if TYPE_CHECKING:
+ import pandas as pd
+ from fastai.text import (
+ AWD_LSTM,
+ LMDataBunch,
+ Tokenizer,
+ Vocab,
+ language_model_learner,
+ )
# fastai
import fastai
@@ -38,11 +48,11 @@
)
# get dummy data
-imdb = untar_data(URLs.IMDB_SAMPLE)
-dummy_df = pd.read_csv(imdb / "texts.csv")
+imdb: Any = untar_data(URLs.IMDB_SAMPLE)
+dummy_df: "pd.DataFrame" = pd.read_csv(imdb / "texts.csv")
# get vocab
-thwiki = THWIKI_LSTM
+thwiki: dict[str, Any] = THWIKI_LSTM
# Validate that corpus files are available
if thwiki["itos_fname"] is None or thwiki["wgts_fname"] is None:
@@ -58,21 +68,21 @@
# Users should only use corpus files from trusted sources.
# WARNING: Pickle deserialization can execute arbitrary code if the file is malicious.
with open(thwiki["itos_fname"], "rb") as f:
- thwiki_itos = pickle.load(f) # noqa: S301
-thwiki_vocab = fastai.text.transform.Vocab(thwiki_itos)
+ thwiki_itos: list[str] = pickle.load(f) # noqa: S301
+thwiki_vocab: "Vocab" = fastai.text.transform.Vocab(thwiki_itos)
# dummy databunch
-tt = Tokenizer(
+tt: "Tokenizer" = Tokenizer(
tok_func=ThaiTokenizer,
lang="th",
pre_rules=pre_rules_th,
post_rules=post_rules_th,
)
-processor = [
+processor: list[Any] = [
TokenizeProcessor(tokenizer=tt, chunksize=10000, mark_fields=False),
NumericalizeProcessor(vocab=thwiki_vocab, max_vocab=60000, min_freq=3),
]
-data_lm = (
+data_lm: "LMDataBunch" = (
TextList.from_df(dummy_df, imdb, cols=["text"], processor=processor)
.split_by_rand_pct(0.2)
.label_for_lm()
@@ -82,7 +92,7 @@
data_lm.sanity_check()
-config = {
+config: dict[str, Any] = {
"emb_sz": 400,
"n_hid": 1550,
"n_layers": 4,
@@ -96,9 +106,14 @@
"embed_p": 0.02,
"weight_p": 0.15,
}
-trn_args = {"drop_mult": 0.9, "clip": 0.12, "alpha": 2, "beta": 1}
+trn_args: dict[str, Any] = {
+ "drop_mult": 0.9,
+ "clip": 0.12,
+ "alpha": 2,
+ "beta": 1,
+}
-learn = language_model_learner(
+learn: Any = language_model_learner(
data_lm, AWD_LSTM, config=config, pretrained=False, **trn_args
)
diff --git a/pythainlp/phayathaibert/__init__.py b/pythainlp/phayathaibert/__init__.py
index 657730ab2..6e6560b3f 100644
--- a/pythainlp/phayathaibert/__init__.py
+++ b/pythainlp/phayathaibert/__init__.py
@@ -3,7 +3,7 @@
# SPDX-License-Identifier: Apache-2.0
"""PhayaThaiBERT"""
-__all__ = [
+__all__: list[str] = [
"NamedEntityTagger",
"PartOfSpeechTagger",
"ThaiTextAugmenter",
diff --git a/pythainlp/phayathaibert/core.py b/pythainlp/phayathaibert/core.py
index 8056b75e9..79652a021 100644
--- a/pythainlp/phayathaibert/core.py
+++ b/pythainlp/phayathaibert/core.py
@@ -7,7 +7,10 @@
import re
import warnings
from collections.abc import Callable
-from typing import Union
+from typing import TYPE_CHECKING, Union
+
+if TYPE_CHECKING:
+ from transformers import CamembertTokenizer
from transformers import (
CamembertTokenizer,
@@ -15,10 +18,12 @@
from pythainlp.tokenize import word_tokenize
-_PAT_URL = r"(http|ftp|https)://([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?"
+_PAT_URL: str = r"(http|ftp|https)://([\w_-]+(?:(?:\.[\w_-]+)+))([\w.,@?^=%&:/~+#-]*[\w@?^=%&/~+#-])?"
-_model_name = "clicknext/phayathaibert"
-_tokenizer = CamembertTokenizer.from_pretrained(_model_name)
+_model_name: str = "clicknext/phayathaibert"
+_tokenizer: "CamembertTokenizer" = CamembertTokenizer.from_pretrained(
+ _model_name
+)
class ThaiTextProcessor:
@@ -206,10 +211,12 @@ def __init__(self) -> None:
pipeline,
)
- self.tokenizer: AutoTokenizer = AutoTokenizer.from_pretrained(_model_name) # type: ignore[assignment]
- self.model_for_masked_lm: AutoModelForMaskedLM = AutoModelForMaskedLM.from_pretrained(
+ self.tokenizer: AutoTokenizer = AutoTokenizer.from_pretrained(
_model_name
) # type: ignore[assignment]
+ self.model_for_masked_lm: AutoModelForMaskedLM = (
+ AutoModelForMaskedLM.from_pretrained(_model_name)
+ ) # type: ignore[assignment]
self.model: any = pipeline( # transformers.Pipeline
"fill-mask",
tokenizer=self.tokenizer,
@@ -304,7 +311,9 @@ def __init__(self, model: str = "lunarlist/pos_thai_phayathai") -> None:
)
self.tokenizer: AutoTokenizer = AutoTokenizer.from_pretrained(model) # type: ignore[assignment]
- self.model: AutoModelForTokenClassification = AutoModelForTokenClassification.from_pretrained(model) # type: ignore[assignment]
+ self.model: AutoModelForTokenClassification = (
+ AutoModelForTokenClassification.from_pretrained(model)
+ ) # type: ignore[assignment]
def get_tag(
self, sentence: str, strategy: str = "simple"
@@ -347,7 +356,9 @@ def __init__(self, model: str = "Pavarissy/phayathaibert-thainer") -> None:
)
self.tokenizer: AutoTokenizer = AutoTokenizer.from_pretrained(model) # type: ignore[assignment]
- self.model: AutoModelForTokenClassification = AutoModelForTokenClassification.from_pretrained(model) # type: ignore[assignment]
+ self.model: AutoModelForTokenClassification = (
+ AutoModelForTokenClassification.from_pretrained(model)
+ ) # type: ignore[assignment]
def get_ner(
self,
diff --git a/pythainlp/spell/phunspell.py b/pythainlp/spell/phunspell.py
index a63287071..6cfb78576 100644
--- a/pythainlp/spell/phunspell.py
+++ b/pythainlp/spell/phunspell.py
@@ -12,6 +12,11 @@
from __future__ import annotations
+from typing import TYPE_CHECKING, Any
+
+if TYPE_CHECKING:
+ import phunspell
+
try:
import phunspell
except ImportError:
@@ -19,7 +24,7 @@
"Import Error; Install phunspell by pip install phunspell"
)
-pspell = phunspell.Phunspell("th_TH")
+pspell: "phunspell.Phunspell" = phunspell.Phunspell("th_TH")
def spell(text: str) -> list[str]:
diff --git a/pythainlp/spell/symspellpy.py b/pythainlp/spell/symspellpy.py
index 1904ed304..a11e1deb8 100644
--- a/pythainlp/spell/symspellpy.py
+++ b/pythainlp/spell/symspellpy.py
@@ -15,6 +15,10 @@
import threading
from importlib.resources import as_file, files
+from typing import TYPE_CHECKING, Any, Optional
+
+if TYPE_CHECKING:
+ from symspellpy import SymSpell
try:
from symspellpy import SymSpell, Verbosity
@@ -25,14 +29,14 @@
from pythainlp.corpus import get_corpus_path
-_UNIGRAM_FILENAME = "tnc_freq.txt"
-_BIGRAM_CORPUS_NAME = "tnc_bigram_word_freqs"
+_UNIGRAM_FILENAME: str = "tnc_freq.txt"
+_BIGRAM_CORPUS_NAME: str = "tnc_bigram_word_freqs"
-_sym_spell = None
-_unigram_file_ctx = (
+_sym_spell: Optional["SymSpell"] = None
+_unigram_file_ctx: Optional[Any] = (
None # File context manager kept alive for program lifetime
)
-_load_lock = threading.Lock() # Thread safety for lazy loading
+_load_lock: threading.Lock = threading.Lock() # Thread safety for lazy loading
def _get_sym_spell() -> SymSpell:
diff --git a/pythainlp/spell/wanchanberta_thai_grammarly.py b/pythainlp/spell/wanchanberta_thai_grammarly.py
index 1f3e5fc6d..69a83ba09 100644
--- a/pythainlp/spell/wanchanberta_thai_grammarly.py
+++ b/pythainlp/spell/wanchanberta_thai_grammarly.py
@@ -22,11 +22,11 @@
)
if TYPE_CHECKING:
- pass
+ from transformers import PreTrainedTokenizer
-use_cuda = torch.cuda.is_available()
-device = torch.device("cuda" if use_cuda else "cpu")
-tokenizer = AutoTokenizer.from_pretrained(
+use_cuda: bool = torch.cuda.is_available()
+device: torch.device = torch.device("cuda" if use_cuda else "cpu")
+tokenizer: "PreTrainedTokenizer" = AutoTokenizer.from_pretrained(
"airesearch/wangchanberta-base-att-spm-uncased"
)
@@ -34,8 +34,10 @@
class BertModel(torch.nn.Module):
def __init__(self) -> None:
super().__init__()
- self.bert: BertForTokenClassification = BertForTokenClassification.from_pretrained(
- "bookpanda/wangchanberta-base-att-spm-uncased-tagging"
+ self.bert: BertForTokenClassification = (
+ BertForTokenClassification.from_pretrained(
+ "bookpanda/wangchanberta-base-att-spm-uncased-tagging"
+ )
)
def forward(
@@ -53,10 +55,10 @@ def forward(
return output
-tagging_model = BertModel()
+tagging_model: BertModel = BertModel()
if use_cuda:
tagging_model = tagging_model.to(device=device)
-ids_to_labels = {0: "f", 1: "i"}
+ids_to_labels: dict[int, str] = {0: "f", 1: "i"}
def align_word_ids(texts: str) -> list[int]:
@@ -97,7 +99,7 @@ def evaluate_one_text(model: BertModel, sentence: str) -> list[str]:
return prediction_label
-mlm_model = AutoModelForMaskedLM.from_pretrained(
+mlm_model: AutoModelForMaskedLM = AutoModelForMaskedLM.from_pretrained(
"bookpanda/wangchanberta-base-att-spm-uncased-masking"
)
if use_cuda:
From 7467d9343ac85ca20e3b26e2a076856823a0a472 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 4 Feb 2026 09:33:46 +0000
Subject: [PATCH 14/17] Plan: Continue type annotations with copilot
instructions noted
Co-authored-by: bact <128572+bact@users.noreply.github.com>
---
.../analysis/output/type_hint_analysis.json | 252 +-----------------
1 file changed, 6 insertions(+), 246 deletions(-)
diff --git a/build_tools/analysis/output/type_hint_analysis.json b/build_tools/analysis/output/type_hint_analysis.json
index efcccd5bf..23060e7f5 100644
--- a/build_tools/analysis/output/type_hint_analysis.json
+++ b/build_tools/analysis/output/type_hint_analysis.json
@@ -11,10 +11,10 @@
},
"variables": {
"total": 1166,
- "complete": 738,
- "none": 428,
- "pct_complete": 63.293310463121784,
- "pct_none": 36.706689536878216,
+ "complete": 778,
+ "none": 388,
+ "pct_complete": 66.7238421955403,
+ "pct_none": 33.27615780445969,
"class_variables": 216,
"instance_variables": 439,
"module_variables": 511
@@ -1721,257 +1721,17 @@
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/cli/__init__.py",
"line": 19
},
- {
- "name": "pythainlp.coref.core._MODEL",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/coref/core.py",
- "line": 8
- },
- {
- "name": "pythainlp.corpus.tnc.__all__",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/tnc.py",
- "line": 8
- },
- {
- "name": "pythainlp.corpus.tnc._UNIGRAM_FILENAME",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/tnc.py",
- "line": 19
- },
- {
- "name": "pythainlp.corpus.tnc._BIGRAM_CORPUS_NAME",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/tnc.py",
- "line": 20
- },
- {
- "name": "pythainlp.corpus.tnc._TRIGRAM_CORPUS_NAME",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/tnc.py",
- "line": 21
- },
- {
- "name": "pythainlp.corpus.ttc.__all__",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/ttc.py",
- "line": 12
- },
- {
- "name": "pythainlp.corpus.ttc._UNIGRAM_FILENAME",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/ttc.py",
- "line": 18
- },
- {
- "name": "pythainlp.corpus.volubilis._VOLUBILIS_WORDS",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/volubilis.py",
- "line": 10
- },
- {
- "name": "pythainlp.corpus.volubilis._VOLUBILIS_FILENAME",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/volubilis.py",
- "line": 11
- },
- {
- "name": "pythainlp.corpus.wikipedia._WIKIPEDIA_TITLES",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/wikipedia.py",
- "line": 10
- },
- {
- "name": "pythainlp.corpus.wikipedia._WIKIPEDIA_TITLES_FILENAME",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/corpus/wikipedia.py",
- "line": 11
- },
- {
- "name": "pythainlp.generate.__all__",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/generate/__init__.py",
- "line": 6
- },
- {
- "name": "pythainlp.generate.thai2fit.__all__",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/generate/thai2fit.py",
- "line": 12
- },
- {
- "name": "pythainlp.generate.thai2fit.imdb",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/generate/thai2fit.py",
- "line": 41
- },
- {
- "name": "pythainlp.generate.thai2fit.dummy_df",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/generate/thai2fit.py",
- "line": 42
- },
- {
- "name": "pythainlp.generate.thai2fit.thwiki",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/generate/thai2fit.py",
- "line": 45
- },
- {
- "name": "pythainlp.generate.thai2fit.thwiki_itos",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/generate/thai2fit.py",
- "line": 61
- },
- {
- "name": "pythainlp.generate.thai2fit.thwiki_vocab",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/generate/thai2fit.py",
- "line": 62
- },
- {
- "name": "pythainlp.generate.thai2fit.tt",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/generate/thai2fit.py",
- "line": 65
- },
- {
- "name": "pythainlp.generate.thai2fit.processor",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/generate/thai2fit.py",
- "line": 71
- },
- {
- "name": "pythainlp.generate.thai2fit.data_lm",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/generate/thai2fit.py",
- "line": 75
- },
- {
- "name": "pythainlp.generate.thai2fit.config",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/generate/thai2fit.py",
- "line": 85
- },
- {
- "name": "pythainlp.generate.thai2fit.trn_args",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/generate/thai2fit.py",
- "line": 99
- },
- {
- "name": "pythainlp.generate.thai2fit.learn",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/generate/thai2fit.py",
- "line": 101
- },
- {
- "name": "pythainlp.phayathaibert.__all__",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/phayathaibert/__init__.py",
- "line": 6
- },
- {
- "name": "pythainlp.phayathaibert.core._PAT_URL",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/phayathaibert/core.py",
- "line": 18
- },
- {
- "name": "pythainlp.phayathaibert.core._model_name",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/phayathaibert/core.py",
- "line": 20
- },
- {
- "name": "pythainlp.phayathaibert.core._tokenizer",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/phayathaibert/core.py",
- "line": 21
- },
- {
- "name": "pythainlp.spell.phunspell.pspell",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/phunspell.py",
- "line": 22
- },
- {
- "name": "pythainlp.spell.symspellpy._UNIGRAM_FILENAME",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/symspellpy.py",
- "line": 28
- },
- {
- "name": "pythainlp.spell.symspellpy._BIGRAM_CORPUS_NAME",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/symspellpy.py",
- "line": 29
- },
- {
- "name": "pythainlp.spell.symspellpy._sym_spell",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/symspellpy.py",
- "line": 31
- },
- {
- "name": "pythainlp.spell.symspellpy._unigram_file_ctx",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/symspellpy.py",
- "line": 32
- },
- {
- "name": "pythainlp.spell.symspellpy._load_lock",
- "scope": "private",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/symspellpy.py",
- "line": 35
- },
- {
- "name": "pythainlp.spell.wanchanberta_thai_grammarly.use_cuda",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/wanchanberta_thai_grammarly.py",
- "line": 27
- },
- {
- "name": "pythainlp.spell.wanchanberta_thai_grammarly.device",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/wanchanberta_thai_grammarly.py",
- "line": 28
- },
- {
- "name": "pythainlp.spell.wanchanberta_thai_grammarly.tokenizer",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/wanchanberta_thai_grammarly.py",
- "line": 29
- },
{
"name": "pythainlp.spell.wanchanberta_thai_grammarly.tagging_model",
"scope": "public",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/wanchanberta_thai_grammarly.py",
- "line": 56
- },
- {
- "name": "pythainlp.spell.wanchanberta_thai_grammarly.tagging_model",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/wanchanberta_thai_grammarly.py",
- "line": 58
- },
- {
- "name": "pythainlp.spell.wanchanberta_thai_grammarly.ids_to_labels",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/wanchanberta_thai_grammarly.py",
- "line": 59
- },
- {
- "name": "pythainlp.spell.wanchanberta_thai_grammarly.mlm_model",
- "scope": "public",
- "file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/wanchanberta_thai_grammarly.py",
- "line": 100
+ "line": 60
},
{
"name": "pythainlp.spell.wanchanberta_thai_grammarly.mlm_model",
"scope": "public",
"file": "/home/runner/work/pythainlp/pythainlp/pythainlp/spell/wanchanberta_thai_grammarly.py",
- "line": 104
+ "line": 106
},
{
"name": "pythainlp.spell.words_spelling_correction._WSC",
From 686c9d9c5a5ed667e0c205f88d9e76c8efe47edf Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 4 Feb 2026 09:36:24 +0000
Subject: [PATCH 15/17] Add type hint to _WSC variable in
words_spelling_correction.py
Added Optional[Any] type annotation to _WSC module variable.
Co-authored-by: bact <128572+bact@users.noreply.github.com>
---
pythainlp/spell/words_spelling_correction.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/pythainlp/spell/words_spelling_correction.py b/pythainlp/spell/words_spelling_correction.py
index 81ab73f77..228303f8f 100644
--- a/pythainlp/spell/words_spelling_correction.py
+++ b/pythainlp/spell/words_spelling_correction.py
@@ -4,7 +4,7 @@
from __future__ import annotations
import os
-from typing import TYPE_CHECKING, Union
+from typing import TYPE_CHECKING, Any, Optional, Union
if TYPE_CHECKING:
import numpy as np
@@ -270,7 +270,7 @@ def __init__(self) -> None:
super().__init__(self.model_path, self.model_onnx, self.list_word)
-_WSC = None
+_WSC: Optional[Any] = None
def get_words_spell_suggestion(
From 8ccc178c0f73412fc5ed141a4453b3f9fd142510 Mon Sep 17 00:00:00 2001
From: Arthit Suriyawongkul
Date: Wed, 4 Feb 2026 09:40:14 +0000
Subject: [PATCH 16/17] Add Union type to imports in core.py
---
pythainlp/coref/core.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pythainlp/coref/core.py b/pythainlp/coref/core.py
index 74726eec6..63078cf90 100644
--- a/pythainlp/coref/core.py
+++ b/pythainlp/coref/core.py
@@ -3,7 +3,7 @@
# SPDX-License-Identifier: Apache-2.0
from __future__ import annotations
-from typing import Any, Optional
+from typing import Any, Optional, Union
_MODEL: Optional[Any] = None
From 1e53fb24ea5f13894789137c486b0936cadf3911 Mon Sep 17 00:00:00 2001
From: Arthit Suriyawongkul
Date: Wed, 4 Feb 2026 09:41:16 +0000
Subject: [PATCH 17/17] Remove unused import of Any from typing
---
pythainlp/spell/phunspell.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/pythainlp/spell/phunspell.py b/pythainlp/spell/phunspell.py
index 6cfb78576..caada60cb 100644
--- a/pythainlp/spell/phunspell.py
+++ b/pythainlp/spell/phunspell.py
@@ -12,7 +12,7 @@
from __future__ import annotations
-from typing import TYPE_CHECKING, Any
+from typing import TYPE_CHECKING
if TYPE_CHECKING:
import phunspell