Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor Python API to be more pythonic #267

Merged
merged 10 commits into from
Jan 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions python/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ msgpack>=1.0.0
pytest>=7.1.1
twine>=4.0.0
wheel>=0.37.1
cython>=3.0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems this file doesn't end with "empty line"

44 changes: 37 additions & 7 deletions python/src/addons/Dictionary.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -40,40 +40,70 @@

def _key_iterator_wrapper(self, iterator):
for m in iterator:
yield m.GetMatchedString()
yield m.matched_string

def _value_iterator_wrapper(self, iterator):
for m in iterator:
yield m.GetValue()
yield m.value

def _item_iterator_wrapper(self, iterator):
for m in iterator:
yield (m.GetMatchedString(), m.GetValue())
yield (m.matched_string, m.value)

def GetAllKeys(self):
def keys(self):
cdef _MatchIteratorPair _r = self.inst.get().GetAllItems()
cdef MatchIterator py_result = MatchIterator.__new__(MatchIterator)
py_result.it = _r.begin()
py_result.end = _r.end()
return self._key_iterator_wrapper(py_result)

def GetAllValues(self):
def GetAllKeys(self):
return call_deprecated_method("GetAllKeys", "keys", self.keys)

def values(self):
cdef _MatchIteratorPair _r = self.inst.get().GetAllItems()
cdef MatchIterator py_result = MatchIterator.__new__(MatchIterator)
py_result.it = _r.begin()
py_result.end = _r.end()
return self._value_iterator_wrapper(py_result)

def GetAllItems(self):
def GetAllValues(self):
return call_deprecated_method("GetAllValues", "values", self.values)

def items(self):
cdef _MatchIteratorPair _r = self.inst.get().GetAllItems()
cdef MatchIterator py_result = MatchIterator.__new__(MatchIterator)
py_result.it = _r.begin()
py_result.end = _r.end()
return self._item_iterator_wrapper(py_result)

def GetStatistics(self):
def GetAllItems(self):
return call_deprecated_method("GetAllItems", "items", self.items)

def statistics(self):
cdef libcpp_string _r = self.inst.get().GetStatistics()
cdef bytes py_result = _r
py_result_unicode = _r.decode('utf-8')

return json.loads(py_result_unicode)

def GetStatistics(self):
return call_deprecated_method("GetStatistics", "statistics", self.statistics)

def GetNear(self, *args):
return call_deprecated_method("GetNear", "match_near", self.match_near, *args)

def Get(self, *args):
return call_deprecated_method("Get", "match", self.match, *args)

def GetFuzzy(self, *args):
return call_deprecated_method("GetFuzzy", "match_fuzzy", self.match_fuzzy, *args)

def Lookup(self, *args):
return call_deprecated_method("Lookup", "search", self.search, *args)

def LookupText(self, *args):
return call_deprecated_method("LookupText", "search_tokenized", self.search_tokenized, *args)

def GetManifest(self, *args):
return call_deprecated_method("GetManifest", "manifest", self.manifest, *args)
113 changes: 103 additions & 10 deletions python/src/addons/Match.pyx
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@


def GetAttribute(self, key):
def GetAttribute(self, *args):
"""deprecated, use index based access"""
return call_deprecated_method("GetAttribute", "[\"{key}\"]", self.__getitem__, *args)


def __getitem__(self, key):
if isinstance(key, unicode):
key = key.encode("utf-8")

py_result = self.inst.get().GetAttributePy(<libcpp_string> key)
return <object>py_result


def SetAttribute(self, key, value):


def SetAttribute(self, *args):
"""deprecated, use index based access"""
return call_deprecated_method("SetAttribute", "[\"{key}\"]", self.__setitem__, *args)


def __setitem__(self, key, value):
if isinstance(key, unicode):
key = key.encode("utf-8")

Expand All @@ -29,15 +39,20 @@
raise Exception("Unsupported Value Type")


def GetValue(self):
"""Decodes a keyvi value and returns it."""
@property
def value(self):
cdef libcpp_string packed_value = self.inst.get().GetMsgPackedValueAsString()
if packed_value.empty():
return None

return msgpack.loads(packed_value)


def GetValue(self, *args):
"""deprecated, use value property"""
return call_deprecated_method_getter("GetValue", "value", self.value, *args)


def dumps(self):
m=[]
do_pack_rest = False
Expand Down Expand Up @@ -74,13 +89,91 @@
if number_of_fields > 0:
m.__SetRawValue(unserialized[0])
if number_of_fields > 1:
m.SetMatchedString(unserialized[1])
m.matched_string = unserialized[1]
if number_of_fields > 2:
m.SetStart(unserialized[2])
m.start = unserialized[2]
if number_of_fields > 3:
m.SetEnd(unserialized[3])
m.end = unserialized[3]
if number_of_fields > 4:
m.SetScore(unserialized[4])
m.score = unserialized[4]

return m

@property
def start(self):
return self.inst.get().GetStart()

@start.setter
def start(self, value):
self.inst.get().SetStart(value)

def GetStart(self, *args):
"""deprecated, use start property"""
return call_deprecated_method_getter("GetStart", "start", self.start, *args)

def SetStart(self, value):
"""deprecated, use start property"""
return call_deprecated_method_setter("SetStart", "start", lambda x : self.inst.get().SetStart(x), value)

@property
def end(self):
return self.inst.get().GetEnd()

@end.setter
def end(self, value):
self.inst.get().SetEnd(value)

def GetEnd(self, *args):
"""deprecated, use end property"""
return call_deprecated_method_getter("GetEnd", "end", self.end, *args)

def SetEnd(self, value):
"""deprecated, use end property"""
return call_deprecated_method_setter("SetEnd", "end", lambda x : self.inst.get().SetEnd(x), value)

@property
def score(self):
return self.inst.get().GetScore()

@score.setter
def score(self, value):
self.inst.get().SetScore(value)

def GetScore(self, *args):
"""deprecated, use score property"""
return call_deprecated_method_getter("GetScore", "score", self.score, *args)

def SetScore(self, value):
"""deprecated, use score property"""
return call_deprecated_method_setter("SetScore", "score", lambda x : self.inst.get().SetScore(x), value)

@property
def matched_string(self):
return self.inst.get().GetMatchedString().decode('utf-8')

@matched_string.setter
def matched_string(self, value):
self.inst.get().SetMatchedString(value)

def GetMatchedString(self, *args):
"""deprecated, use matched_string property"""
return call_deprecated_method_getter("GetMatchedString", "matched_string", self.matched_string, *args)

def SetMatchedString(self, value):
"""deprecated, use matched_string property"""
return call_deprecated_method_setter("SetMatchedString", "matched_string", lambda x : self.inst.get().SetMatchedString(x), value)

def GetValueAsString(self, *args):
"""deprecated, use get_value_as_string"""
return call_deprecated_method("GetValueAsString", "value_as_string", self.value_as_string, *args)

def GetRawValueAsString(self, *args):
"""deprecated, use get_raw_value_as_string"""
return call_deprecated_method("GetRawValueAsString", "raw_value_as_string", self.raw_value_as_string, *args)

def __bool__(self):
return not self.inst.get().IsEmpty()

def IsEmpty(self, *args):
"""deprecated, use bool operator"""
return not call_deprecated_method("IsEmpty", "__bool__", self.__bool__, *args)
16 changes: 16 additions & 0 deletions python/src/addons/autwrap_workarounds.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import msgpack
import keyvi._pycore
import os.path
import sys
import warnings


def get_package_root():
Expand All @@ -38,3 +39,18 @@ def get_interpreter_executable():
# definition for all compilers
cdef void progress_compiler_callback(size_t a, size_t b, void* py_callback) noexcept with gil:
(<object>py_callback)(a, b)

def call_deprecated_method(deprecated_method_name, new_method_name, new_method, *args):
msg = f"{deprecated_method_name} is deprecated and will be removed in a future version. Use {new_method_name} instead."
warnings.warn(msg, DeprecationWarning)
return new_method(*args)

def call_deprecated_method_setter(deprecated_method_name, new_method_name, setter, value):
msg = f"{deprecated_method_name} is deprecated and will be removed in a future version. Use {new_method_name} instead."
warnings.warn(msg, DeprecationWarning)
setter(value)

def call_deprecated_method_getter(deprecated_method_name, new_method_name, getter):
msg = f"{deprecated_method_name} is deprecated and will be removed in a future version. Use {new_method_name} instead."
warnings.warn(msg, DeprecationWarning)
return getter
16 changes: 8 additions & 8 deletions python/src/pxds/dictionary.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,14 @@ cdef extern from "keyvi/dictionary/dictionary.h" namespace "keyvi::dictionary":
Dictionary (libcpp_utf8_string filename, loading_strategy_types) except +
bool Contains (libcpp_utf8_string) # wrap-ignore
Match operator[](libcpp_utf8_string) # wrap-ignore
_MatchIteratorPair Get (libcpp_utf8_string)
_MatchIteratorPair GetNear (libcpp_utf8_string, size_t minimum_prefix_length) except +
_MatchIteratorPair GetNear (libcpp_utf8_string, size_t minimum_prefix_length, bool greedy) except +
_MatchIteratorPair GetFuzzy (libcpp_utf8_string, int32_t max_edit_distance) except +
_MatchIteratorPair GetFuzzy (libcpp_utf8_string, int32_t max_edit_distance, size_t minimum_exact_prefix) except +
_MatchIteratorPair Get (libcpp_utf8_string) # wrap-as:match
_MatchIteratorPair GetNear (libcpp_utf8_string, size_t minimum_prefix_length) except + # wrap-as:match_near
_MatchIteratorPair GetNear (libcpp_utf8_string, size_t minimum_prefix_length, bool greedy) except + # wrap-as:match_near
_MatchIteratorPair GetFuzzy (libcpp_utf8_string, int32_t max_edit_distance) except + # wrap-as:match_fuzzy
_MatchIteratorPair GetFuzzy (libcpp_utf8_string, int32_t max_edit_distance, size_t minimum_exact_prefix) except + # wrap-as:match_fuzzy
_MatchIteratorPair GetAllItems () # wrap-ignore
_MatchIteratorPair Lookup(libcpp_utf8_string)
_MatchIteratorPair LookupText(libcpp_utf8_string)
libcpp_utf8_output_string GetManifest() except +
_MatchIteratorPair Lookup(libcpp_utf8_string) # wrap-as:search
_MatchIteratorPair LookupText(libcpp_utf8_string) # wrap-as:search_tokenized
libcpp_utf8_output_string GetManifest() except + # wrap-as:manifest
libcpp_string GetStatistics() # wrap-ignore
uint64_t GetSize() # wrap-ignore
22 changes: 11 additions & 11 deletions python/src/pxds/match.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,22 @@ cdef extern from "keyvi/dictionary/match.h" namespace "keyvi::dictionary":
cdef cppclass Match:
Match()
Match(Match& m)
size_t GetStart()
void SetStart(size_t start)
size_t GetEnd()
void SetEnd(size_t end)
float GetScore()
void SetScore(float score)
libcpp_utf8_output_string GetMatchedString()
void SetMatchedString (libcpp_utf8_string matched_string)
size_t GetStart() # wrap-ignore
void SetStart(size_t start) # wrap-ignore
size_t GetEnd() # wrap-ignore
void SetEnd(size_t end) # wrap-ignore
float GetScore() # wrap-ignore
void SetScore(float score) # wrap-ignore
libcpp_utf8_output_string GetMatchedString() # wrap-ignore
void SetMatchedString (libcpp_utf8_string matched_string) # wrap-ignore
PyObject* GetAttributePy(libcpp_utf8_string) except + nogil # wrap-ignore
libcpp_utf8_output_string GetValueAsString() except +
libcpp_string GetRawValueAsString() except +
libcpp_utf8_output_string GetValueAsString() except + # wrap-as:value_as_string
libcpp_string GetRawValueAsString() except + # wrap-as:raw_value_as_string
libcpp_string GetMsgPackedValueAsString() except + # wrap-ignore
void SetRawValue(libcpp_utf8_string) except + # wrap-ignore
void SetAttribute(libcpp_utf8_string, libcpp_utf8_string) except + # wrap-ignore
void SetAttribute(libcpp_utf8_string, float) except + # wrap-ignore
void SetAttribute(libcpp_utf8_string, int) except + # wrap-ignore
void SetAttribute(libcpp_utf8_string, bool) except + # wrap-ignore
bool IsEmpty()
bool IsEmpty() # wrap-ignore

Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def test_forward_backward_completion():
with tmp_dictionary(c, 'fw_bw_completion.kv') as d:
with tmp_dictionary(c_bw, 'fw_bw_completion_bw.kv') as d2:
completer = ForwardBackwardCompletion(d, d2)
matches = sorted([(match.GetAttribute('weight'), match.GetMatchedString())
matches = sorted([(match['weight'], match.matched_string)
for match in completer.GetCompletions("munich")], reverse=True)
assert len(matches) == 2
assert matches[0][1] == 'bayern munich vs. real madrid'
Expand Down
26 changes: 13 additions & 13 deletions python/tests/completion/fuzzy_completion_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,34 +40,34 @@ def test_fuzzy_completion():

with tmp_dictionary(c, 'fuzzy_completion.kv') as d:
completer = PrefixCompletion(d)
matches = [m.GetMatchedString() for m in completer.GetFuzzyCompletions('tuv', 0)]
matches = [m.matched_string for m in completer.GetFuzzyCompletions('tuv', 0)]
assert len(matches) == 9

matches = [m.GetMatchedString() for m in completer.GetFuzzyCompletions('tue', 1)]
matches = [m.matched_string for m in completer.GetFuzzyCompletions('tue', 1)]
assert len(matches) == 1

matches = [m.GetMatchedString() for m in completer.GetFuzzyCompletions('tuv h', 1)]
matches = [m.matched_string for m in completer.GetFuzzyCompletions('tuv h', 1)]
assert len(matches) == 2

matches = [m.GetMatchedString() for m in completer.GetFuzzyCompletions('tuv h', 2)]
matches = [m.matched_string for m in completer.GetFuzzyCompletions('tuv h', 2)]
assert len(matches) == 7

matches = [m.GetMatchedString() for m in completer.GetFuzzyCompletions('tuk töffnungszeiten', 2)]
matches = [m.matched_string for m in completer.GetFuzzyCompletions('tuk töffnungszeiten', 2)]
assert len(matches) == 1

matches = [m.GetMatchedString() for m in completer.GetFuzzyCompletions('tuk töffnung', 2)]
matches = [m.matched_string for m in completer.GetFuzzyCompletions('tuk töffnung', 2)]
assert len(matches) == 1

matches = [m.GetMatchedString() for m in completer.GetFuzzyCompletions('tuk txyzöff', 5)]
matches = [m.matched_string for m in completer.GetFuzzyCompletions('tuk txyzöff', 5)]
assert len(matches) == 1

matches = [m.GetMatchedString() for m in completer.GetFuzzyCompletions('tuk txyzöffnung', 5)]
matches = [m.matched_string for m in completer.GetFuzzyCompletions('tuk txyzöffnung', 5)]
assert len(matches) == 1

matches = [m.GetMatchedString() for m in completer.GetFuzzyCompletions('tuk txyzvöffnung', 6)]
matches = [m.matched_string for m in completer.GetFuzzyCompletions('tuk txyzvöffnung', 6)]
assert len(matches) == 1

matches = [m.GetMatchedString() for m in completer.GetFuzzyCompletions('tuk ffnung', 2)]
matches = [m.matched_string for m in completer.GetFuzzyCompletions('tuk ffnung', 2)]
assert len(matches) == 1


Expand All @@ -78,11 +78,11 @@ def test_fuzzy_completion_utf8():
with tmp_dictionary(c, 'fuzzy_completion_utf8.kv') as d:
completer = PrefixCompletion(d)

matches = [m.GetMatchedString() for m in completer.GetFuzzyCompletions('mß', 1)]
matches = [m.matched_string for m in completer.GetFuzzyCompletions('mß', 1)]
assert len(matches) == 1

matches = [m.GetMatchedString() for m in completer.GetFuzzyCompletions('mß', 1, 0)]
matches = [m.matched_string for m in completer.GetFuzzyCompletions('mß', 1, 0)]
assert len(matches) == 1

matches = [m.GetMatchedString() for m in completer.GetFuzzyCompletions('mß', 1, 4)]
matches = [m.matched_string for m in completer.GetFuzzyCompletions('mß', 1, 4)]
assert len(matches) == 1
Loading
Loading