diff --git a/README.kr.rst b/README.kr.rst index 4b01f70..42c85f4 100644 --- a/README.kr.rst +++ b/README.kr.rst @@ -30,7 +30,7 @@ tomotopy 란? 더 자세한 정보는 https://bab2min.github.io/tomotopy/index.kr.html 에서 확인하시길 바랍니다. -tomotopy의 가장 최신버전은 0.4.0 입니다. +tomotopy의 가장 최신버전은 0.4.1 입니다. 시작하기 --------------- @@ -197,6 +197,9 @@ tomotopy의 Python3 예제 코드는 https://github.com/bab2min/tomotopy/blob/ma 역사 ------- +* 0.4.1 (2019-11-27) + * `tomotopy.PLDAModel` 생성자의 버그를 수정했습니다. + * 0.4.0 (2019-11-18) * `tomotopy.PLDAModel`와 `tomotopy.HLDAModel` 토픽 모델이 새로 추가되었습니다. diff --git a/README.rst b/README.rst index 2062c66..212676b 100644 --- a/README.rst +++ b/README.rst @@ -31,7 +31,7 @@ The current version of `tomoto` supports several major topic models including Please visit https://bab2min.github.io/tomotopy to see more information. -The most recent version of tomotopy is 0.4.0. +The most recent version of tomotopy is 0.4.1. Getting Started --------------- @@ -202,6 +202,9 @@ meaning you can use it for any reasonable purpose and remain in complete ownersh History ------- +* 0.4.1 (2019-11-27) + * A bug at init function of `tomotopy.PLDAModel` was fixed. + * 0.4.0 (2019-11-18) * New models including `tomotopy.PLDAModel` and `tomotopy.HLDAModel` were added into the package. diff --git a/setup.py b/setup.py index 957f7cb..162a769 100644 --- a/setup.py +++ b/setup.py @@ -50,7 +50,7 @@ setup( name='tomotopy', - version='0.4.0', + version='0.4.1', description='Tomoto, The Topic Modeling Tool for Python', long_description=long_description, diff --git a/src/python/PyUtils.h b/src/python/PyUtils.h index 6e7061b..82db48b 100644 --- a/src/python/PyUtils.h +++ b/src/python/PyUtils.h @@ -1,10 +1,14 @@ #pragma once #include +#include #include #include #include +#include #include #include +#include +#include namespace py { @@ -184,4 +188,36 @@ namespace py } return ret; } -} \ No newline at end of file + + class WarningLog + { + std::set> printed; + + WarningLog() + { + } + public: + static WarningLog& get() + { + thread_local WarningLog inst; + return inst; + } + + void printOnce(std::ostream& ostr, const std::string& msg) + { + auto frame = PyEval_GetFrame(); + auto key = std::make_tuple( + std::string{ PyUnicode_AsUTF8(frame->f_code->co_filename) }, + PyFrame_GetLineNumber(frame), + msg); + + if (!printed.count(key)) + { + ostr << std::get<0>(key) << "(" << std::get<1>(key) << "): " << std::get<2>(key) << std::endl; + printed.insert(key); + } + } + }; +} + +#define PRINT_WARN(msg) do{ py::WarningLog::get().printOnce(std::cerr, msg); } while(0) diff --git a/src/python/py_DMR.cpp b/src/python/py_DMR.cpp index b55a66c..4e45597 100644 --- a/src/python/py_DMR.cpp +++ b/src/python/py_DMR.cpp @@ -41,6 +41,7 @@ static PyObject* DMR_addDoc(TopicModelObject* self, PyObject* args, PyObject *kw if (!self->inst) throw runtime_error{ "inst is null" }; if (self->isPrepared) throw runtime_error{ "cannot add_doc() after train()" }; auto* inst = static_cast(self->inst); + if (PyUnicode_Check(argWords)) PRINT_WARN("[warn] 'words' should be an iterable of str."); if (!(iter = PyObject_GetIter(argWords))) { throw runtime_error{ "words must be an iterable of str." }; @@ -71,6 +72,7 @@ static PyObject* DMR_makeDoc(TopicModelObject* self, PyObject* args, PyObject *k { if (!self->inst) throw runtime_error{ "inst is null" }; auto* inst = static_cast(self->inst); + if (PyUnicode_Check(argWords)) PRINT_WARN("[warn] 'words' should be an iterable of str."); if (!(iter = PyObject_GetIter(argWords))) { throw runtime_error{ "words must be an iterable of str." }; diff --git a/src/python/py_LDA.cpp b/src/python/py_LDA.cpp index 9a43051..7713c8f 100644 --- a/src/python/py_LDA.cpp +++ b/src/python/py_LDA.cpp @@ -42,6 +42,7 @@ static PyObject* LDA_addDoc(TopicModelObject* self, PyObject* args, PyObject *kw if (!self->inst) throw runtime_error{ "inst is null" }; if (self->isPrepared) throw runtime_error{ "cannot add_doc() after train()" }; auto* inst = static_cast(self->inst); + if (PyUnicode_Check(argWords)) PRINT_WARN("[warn] 'words' should be an iterable of str."); if (!(iter = PyObject_GetIter(argWords))) { throw runtime_error{ "words must be an iterable of str." }; @@ -70,6 +71,7 @@ static PyObject* LDA_makeDoc(TopicModelObject* self, PyObject* args, PyObject *k { if (!self->inst) throw runtime_error{ "inst is null" }; auto* inst = static_cast(self->inst); + if (PyUnicode_Check(argWords)) PRINT_WARN("[warn] 'words' should be an iterable of str."); if (!(iter = PyObject_GetIter(argWords))) { throw runtime_error{ "words must be an iterable of str." }; diff --git a/src/python/py_LLDA.cpp b/src/python/py_LLDA.cpp index 5a50dc6..fe0341e 100644 --- a/src/python/py_LLDA.cpp +++ b/src/python/py_LLDA.cpp @@ -40,6 +40,7 @@ static PyObject* LLDA_addDoc(TopicModelObject* self, PyObject* args, PyObject *k if (!self->inst) throw runtime_error{ "inst is null" }; if (self->isPrepared) throw runtime_error{ "cannot add_doc() after train()" }; auto* inst = static_cast(self->inst); + if (PyUnicode_Check(argWords)) PRINT_WARN("[warn] 'words' should be an iterable of str."); if (!(iter = PyObject_GetIter(argWords))) { throw runtime_error{ "words must be an iterable of str." }; @@ -48,9 +49,10 @@ static PyObject* LLDA_addDoc(TopicModelObject* self, PyObject* args, PyObject *k vector labels; if(argLabels) { + if (PyUnicode_Check(argLabels)) PRINT_WARN("[warn] 'labels' should be an iterable of str."); if (!(iter2 = PyObject_GetIter(argLabels))) { - throw runtime_error{ "words must be an iterable of str." }; + throw runtime_error{ "'labels' must be an iterable of str." }; } py::AutoReleaser arIter2{ iter2 }; labels = py::makeIterToVector(iter2); @@ -78,6 +80,7 @@ static PyObject* LLDA_makeDoc(TopicModelObject* self, PyObject* args, PyObject * { if (!self->inst) throw runtime_error{ "inst is null" }; auto* inst = static_cast(self->inst); + if (PyUnicode_Check(argWords)) PRINT_WARN("[warn] 'words' should be an iterable of str."); if (!(iter = PyObject_GetIter(argWords))) { throw runtime_error{ "words must be an iterable of str." }; @@ -86,9 +89,10 @@ static PyObject* LLDA_makeDoc(TopicModelObject* self, PyObject* args, PyObject * vector labels; if (argLabels) { + if (PyUnicode_Check(argLabels)) PRINT_WARN("[warn] 'labels' should be an iterable of str."); if (!(iter2 = PyObject_GetIter(argLabels))) { - throw runtime_error{ "words must be an iterable of str." }; + throw runtime_error{ "'labels' must be an iterable of str." }; } py::AutoReleaser arIter2{ iter2 }; labels = py::makeIterToVector(iter2); diff --git a/src/python/py_MGLDA.cpp b/src/python/py_MGLDA.cpp index c39721f..f67f119 100644 --- a/src/python/py_MGLDA.cpp +++ b/src/python/py_MGLDA.cpp @@ -44,6 +44,7 @@ static PyObject* MGLDA_addDoc(TopicModelObject* self, PyObject* args, PyObject * if (!self->inst) throw runtime_error{ "inst is null" }; if (self->isPrepared) throw runtime_error{ "cannot add_doc() after train()" }; auto* inst = static_cast(self->inst); + if (PyUnicode_Check(argWords)) PRINT_WARN("[warn] 'words' should be an iterable of str."); if (!(iter = PyObject_GetIter(argWords))) { throw runtime_error{ "words must be an iterable of str." }; @@ -73,6 +74,7 @@ static PyObject* MGLDA_makeDoc(TopicModelObject* self, PyObject* args, PyObject { if (!self->inst) throw runtime_error{ "inst is null" }; auto* inst = static_cast(self->inst); + if (PyUnicode_Check(argWords)) PRINT_WARN("[warn] 'words' should be an iterable of str."); if (!(iter = PyObject_GetIter(argWords))) { throw runtime_error{ "words must be an iterable of str." }; diff --git a/src/python/py_PLDA.cpp b/src/python/py_PLDA.cpp index a0e206a..6c70728 100644 --- a/src/python/py_PLDA.cpp +++ b/src/python/py_PLDA.cpp @@ -11,7 +11,7 @@ static int PLDA_init(TopicModelObject *self, PyObject *args, PyObject *kwargs) float alpha = 0.1, eta = 0.01, sigma = 1, alphaEpsilon = 1e-10; size_t seed = random_device{}(); static const char* kwlist[] = { "tw", "min_cf", "rm_top", "latent_topics", "topics_per_label", "alpha", "eta", "seed", nullptr }; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|nnnnffffn", (char**)kwlist, &tw, &minCnt, &rmTop, + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|nnnnnffn", (char**)kwlist, &tw, &minCnt, &rmTop, &numLatentTopics, &numTopicsPerLabel, &alpha, &eta, &seed)) return -1; try { @@ -41,6 +41,7 @@ static PyObject* PLDA_addDoc(TopicModelObject* self, PyObject* args, PyObject *k if (!self->inst) throw runtime_error{ "inst is null" }; if (self->isPrepared) throw runtime_error{ "cannot add_doc() after train()" }; auto* inst = static_cast(self->inst); + if (PyUnicode_Check(argWords)) PRINT_WARN("[warn] 'words' should be an iterable of str."); if (!(iter = PyObject_GetIter(argWords))) { throw runtime_error{ "words must be an iterable of str." }; @@ -49,9 +50,10 @@ static PyObject* PLDA_addDoc(TopicModelObject* self, PyObject* args, PyObject *k vector labels; if(argLabels) { + if (PyUnicode_Check(argLabels)) PRINT_WARN("[warn] 'labels' should be an iterable of str."); if (!(iter2 = PyObject_GetIter(argLabels))) { - throw runtime_error{ "words must be an iterable of str." }; + throw runtime_error{ "'labels' must be an iterable of str." }; } py::AutoReleaser arIter2{ iter2 }; labels = py::makeIterToVector(iter2); @@ -79,6 +81,7 @@ static PyObject* PLDA_makeDoc(TopicModelObject* self, PyObject* args, PyObject * { if (!self->inst) throw runtime_error{ "inst is null" }; auto* inst = static_cast(self->inst); + if (PyUnicode_Check(argWords)) PRINT_WARN("[warn] 'words' should be an iterable of str."); if (!(iter = PyObject_GetIter(argWords))) { throw runtime_error{ "words must be an iterable of str." }; @@ -87,9 +90,10 @@ static PyObject* PLDA_makeDoc(TopicModelObject* self, PyObject* args, PyObject * vector labels; if (argLabels) { + if (PyUnicode_Check(argLabels)) PRINT_WARN("[warn] 'labels' should be an iterable of str."); if (!(iter2 = PyObject_GetIter(argLabels))) { - throw runtime_error{ "words must be an iterable of str." }; + throw runtime_error{ "'labels' must be an iterable of str." }; } py::AutoReleaser arIter2{ iter2 }; labels = py::makeIterToVector(iter2); diff --git a/src/python/py_SLDA.cpp b/src/python/py_SLDA.cpp index 64b294f..9f4a300 100644 --- a/src/python/py_SLDA.cpp +++ b/src/python/py_SLDA.cpp @@ -115,6 +115,7 @@ static PyObject* SLDA_addDoc(TopicModelObject* self, PyObject* args, PyObject *k if (!self->inst) throw runtime_error{ "inst is null" }; if (self->isPrepared) throw runtime_error{ "cannot add_doc() after train()" }; auto* inst = static_cast(self->inst); + if (PyUnicode_Check(argWords)) PRINT_WARN("[warn] 'words' should be an iterable of str."); if (!(iter = PyObject_GetIter(argWords))) { throw runtime_error{ "'words' must be an iterable of str." }; @@ -151,6 +152,7 @@ static PyObject* SLDA_makeDoc(TopicModelObject* self, PyObject* args, PyObject * { if (!self->inst) throw runtime_error{ "inst is null" }; auto* inst = static_cast(self->inst); + if (PyUnicode_Check(argWords)) PRINT_WARN("[warn] 'words' should be an iterable of str."); if (!(iter = PyObject_GetIter(argWords))) { throw runtime_error{ "words must be an iterable of str." }; diff --git a/tomotopy/documentation.kr.rst b/tomotopy/documentation.kr.rst index 91cd0a8..c55c1c8 100644 --- a/tomotopy/documentation.kr.rst +++ b/tomotopy/documentation.kr.rst @@ -16,7 +16,7 @@ tomotopy 란? * Hierarchical PA (`tomotopy.HPAModel`) * Correlated Topic Model (`tomotopy.CTModel`) -tomotopy의 가장 최신버전은 0.4.0 입니다. +tomotopy의 가장 최신버전은 0.4.1 입니다. .. image:: https://badge.fury.io/py/tomotopy.svg @@ -239,6 +239,9 @@ tomotopy의 Python3 예제 코드는 https://github.com/bab2min/tomotopy/blob/ma 역사 ------- +* 0.4.1 (2019-11-27) + * `tomotopy.PLDAModel` 생성자의 버그를 수정했습니다. + * 0.4.0 (2019-11-18) * `tomotopy.PLDAModel`와 `tomotopy.HLDAModel` 토픽 모델이 새로 추가되었습니다. diff --git a/tomotopy/documentation.rst b/tomotopy/documentation.rst index 43b6681..07c6b2b 100644 --- a/tomotopy/documentation.rst +++ b/tomotopy/documentation.rst @@ -16,7 +16,7 @@ The current version of `tomoto` supports several major topic models including * Hierarchical PA (`tomotopy.HPAModel`) * Correlated Topic Model (`tomotopy.CTModel`). -The most recent version of tomotopy is 0.4.0. +The most recent version of tomotopy is 0.4.1. .. image:: https://badge.fury.io/py/tomotopy.svg @@ -242,6 +242,9 @@ meaning you can use it for any reasonable purpose and remain in complete ownersh History ------- +* 0.4.1 (2019-11-27) + * A bug at init function of `tomotopy.PLDAModel` was fixed. + * 0.4.0 (2019-11-18) * New models including `tomotopy.PLDAModel` and `tomotopy.HLDAModel` were added into the package.