Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-pylev for openSUSE:Factory checked in at 2022-10-08 01:25:19 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-pylev (Old) and /work/SRC/openSUSE:Factory/.python-pylev.new.2275 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-pylev" Sat Oct 8 01:25:19 2022 rev:3 rq:1008701 version:1.4.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-pylev/python-pylev.changes 2021-06-01 10:33:42.712429991 +0200 +++ /work/SRC/openSUSE:Factory/.python-pylev.new.2275/python-pylev.changes 2022-10-08 01:25:34.426277652 +0200 @@ -1,0 +2,6 @@ +Wed Oct 5 00:20:54 UTC 2022 - Yogalakshmi Arunachalam <yarunacha...@suse.com> + +- Update to v1.4.0 + Bumped to 1.4.0! + +------------------------------------------------------------------- Old: ---- pylev-1.3.0.tar.gz New: ---- pylev-1.4.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-pylev.spec ++++++ --- /var/tmp/diff_new_pack.Ul8c2S/_old 2022-10-08 01:25:36.514282440 +0200 +++ /var/tmp/diff_new_pack.Ul8c2S/_new 2022-10-08 01:25:36.518282449 +0200 @@ -1,7 +1,7 @@ # # spec file for package python-pylev # -# Copyright (c) 2021 SUSE LLC +# Copyright (c) 2022 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -18,7 +18,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} Name: python-pylev -Version: 1.3.0 +Version: 1.4.0 Release: 0 Summary: A pure Python Levenshtein implementation License: BSD-3-Clause ++++++ pylev-1.3.0.tar.gz -> pylev-1.4.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylev-1.3.0/LICENSE new/pylev-1.4.0/LICENSE --- old/pylev-1.3.0/LICENSE 1970-01-01 01:00:00.000000000 +0100 +++ new/pylev-1.4.0/LICENSE 2021-05-30 20:41:51.000000000 +0200 @@ -0,0 +1,25 @@ +Copyright (c) 2012, Daniel Lindsley +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the pylev nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL pylev BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylev-1.3.0/MANIFEST.in new/pylev-1.4.0/MANIFEST.in --- old/pylev-1.3.0/MANIFEST.in 1970-01-01 01:00:00.000000000 +0100 +++ new/pylev-1.4.0/MANIFEST.in 2021-05-30 21:24:05.000000000 +0200 @@ -0,0 +1,3 @@ +include bench.sh +include LICENSE +include README.rst diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylev-1.3.0/PKG-INFO new/pylev-1.4.0/PKG-INFO --- old/pylev-1.3.0/PKG-INFO 2014-10-23 02:24:16.000000000 +0200 +++ new/pylev-1.4.0/PKG-INFO 2021-05-30 22:05:22.000000000 +0200 @@ -1,87 +1,11 @@ -Metadata-Version: 1.1 +Metadata-Version: 2.1 Name: pylev -Version: 1.3.0 +Version: 1.4.0 Summary: A pure Python Levenshtein implementation that's not freaking GPL'd. Home-page: http://github.com/toastdriven/pylev Author: Daniel Lindsley Author-email: dan...@toastdriven.com License: UNKNOWN -Description: pylev - ===== - - A pure Python Levenshtein implementation that's not freaking GPL'd. - - Based off the Wikipedia code samples at - http://en.wikipedia.org/wiki/Levenshtein_distance. - - - Requirements - ------------ - - * Python 2.7.X, Python 3.3+ or PyPy 1.6.0+ - - - Usage - ----- - - Usage is fairly straightforward.:: - - import pylev - distance = pylev.levenshtein('kitten', 'sitting') - assert(distance, 3) - - - License - ------- - - New BSD. - - - Tests - ----- - - Setup:: - - $ git clone https://github.com/toastdriven/pylev.git - $ cd pylev - - Running:: - - $ python -m unittest tests - - [](https://travis-ci.org/toastdriven/pylev) - - - Version History - --------------- - - * v1.3.0 - - * Implemented a considerably faster variants (orders of magnitude). - * Tested & working on Python 2.7.4, Python 3.3.1 & PyPy 1.9.0. - - * v1.2.0 - - * Fixed all incorrect spellings of "Levenshtein" (there's no "c" in it). - * Old methods are aliased for backward-compatibility. - - * v1.1.0 - - * Implemented a much faster variant (several orders of magnitude). - * The older variant was renamed to ``classic_levenschtein``. - * Tested & working on Python 3.3 & PyPy 1.6.0 as well. - - * v1.0.2 - - * Python packaging is **REALLY** hard. Including the README *this time*. - - * v1.0.1 - - * Python packaging is hard. Including the README this time. - - * v1.0.0 - - * Initial release, just the naive implementation of Levenshtein. Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers @@ -89,3 +13,94 @@ Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 +License-File: LICENSE + +pylev +===== + +A pure Python Levenshtein implementation that's not freaking GPL'd. + +Based off the Wikipedia code samples at +http://en.wikipedia.org/wiki/Levenshtein_distance. + + +Requirements +------------ + +* Python 2.7.X, Python 3.3+ or PyPy 1.6.0+ + + +Usage +----- + +Usage is fairly straightforward: + +.. code-block:: python + + import pylev + distance = pylev.levenshtein('kitten', 'sitting') + assert distance == 3 + + +License +------- + +New BSD. + + +Tests +----- + +Setup:: + + $ git clone https://github.com/toastdriven/pylev.git + $ cd pylev + +Running:: + + $ python -m unittest tests + +.. image:: https://travis-ci.com/toastdriven/pylev.svg?branch=main + :target: http://travis-ci.com/toastdriven/pylev + + +Version History +--------------- + +* v1.4.0 + + * Updated for current versions of Python + * Integrated a better Travis matrix. Thanks to @grainert! + * Fixed mistaken docs about the `assert`. Thanks to @adamchainz! + * Reorganized the package. + * Blacked all the source code. + +* v1.3.0 + + * Implemented a considerably faster variants (orders of magnitude). + * Tested & working on Python 2.7.4, Python 3.3.1 & PyPy 1.9.0. + +* v1.2.0 + + * Fixed all incorrect spellings of "Levenshtein" (there's no "c" in it). + * Old methods are aliased for backward-compatibility. + +* v1.1.0 + + * Implemented a much faster variant (several orders of magnitude). + * The older variant was renamed to ``classic_levenschtein``. + * Tested & working on Python 3.3 & PyPy 1.6.0 as well. + +* v1.0.2 + + * Python packaging is **REALLY** hard. Including the README *this time*. + +* v1.0.1 + + * Python packaging is hard. Including the README this time. + +* v1.0.0 + + * Initial release, just the naive implementation of Levenshtein. + + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylev-1.3.0/README.rst new/pylev-1.4.0/README.rst --- old/pylev-1.3.0/README.rst 2014-10-23 02:24:01.000000000 +0200 +++ new/pylev-1.4.0/README.rst 2021-05-30 21:59:22.000000000 +0200 @@ -16,11 +16,13 @@ Usage ----- -Usage is fairly straightforward.:: +Usage is fairly straightforward: + +.. code-block:: python import pylev distance = pylev.levenshtein('kitten', 'sitting') - assert(distance, 3) + assert distance == 3 License @@ -41,12 +43,21 @@ $ python -m unittest tests -[](https://travis-ci.org/toastdriven/pylev) +.. image:: https://travis-ci.com/toastdriven/pylev.svg?branch=main + :target: http://travis-ci.com/toastdriven/pylev Version History --------------- +* v1.4.0 + + * Updated for current versions of Python + * Integrated a better Travis matrix. Thanks to @grainert! + * Fixed mistaken docs about the `assert`. Thanks to @adamchainz! + * Reorganized the package. + * Blacked all the source code. + * v1.3.0 * Implemented a considerably faster variants (orders of magnitude). @@ -73,4 +84,4 @@ * v1.0.0 - * Initial release, just the naive implementation of Levenshtein. \ No newline at end of file + * Initial release, just the naive implementation of Levenshtein. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylev-1.3.0/bench.sh new/pylev-1.4.0/bench.sh --- old/pylev-1.3.0/bench.sh 1970-01-01 01:00:00.000000000 +0100 +++ new/pylev-1.4.0/bench.sh 2021-05-30 20:41:51.000000000 +0200 @@ -0,0 +1,27 @@ +#!/bin/bash +echo -ne "py2.7 recursive_levenshtein\t\t" +python2.7 -m timeit -s "import pylev" "pylev.recursive_levenshtein('Levenshtein', 'Frankenstein')" +echo -ne "py2.7 wf_levenshtein\t\t\t" +python2.7 -m timeit -s "import pylev" "pylev.wf_levenshtein('Levenshtein', 'Frankenstein')" +echo -ne "py2.7 wfi_levenshtein\t\t\t" +python2.7 -m timeit -s "import pylev" "pylev.wfi_levenshtein('Levenshtein', 'Frankenstein')" +echo -ne "py2.7 damerau_levenshtein\t\t" +python2.7 -m timeit -s "import pylev" "pylev.damerau_levenshtein('Levenshtein', 'Frankenstein')" + +echo -ne "py3.3 recursive_levenshtein\t\t" +python3.3 -m timeit -s "import pylev" "pylev.recursive_levenshtein('Levenshtein', 'Frankenstein')" +echo -ne "py3.3 wf_levenshtein\t\t\t" +python3.3 -m timeit -s "import pylev" "pylev.wf_levenshtein('Levenshtein', 'Frankenstein')" +echo -ne "py3.3 wfi_levenshtein\t\t\t" +python3.3 -m timeit -s "import pylev" "pylev.wfi_levenshtein('Levenshtein', 'Frankenstein')" +echo -ne "py3.3 damerau_levenshtein\t\t" +python3.3 -m timeit -s "import pylev" "pylev.damerau_levenshtein('Levenshtein', 'Frankenstein')" + +echo -ne "pypy recursive_levenshtein\t\t" +pypy -m timeit -s "import pylev" "pylev.recursive_levenshtein('Levenshtein', 'Frankenstein')" +echo -ne "pypy wf_levenshtein\t\t\t" +pypy -m timeit -s "import pylev" "pylev.wf_levenshtein('Levenshtein', 'Frankenstein')" +echo -ne "pypy wfi_levenshtein\t\t\t" +pypy -m timeit -s "import pylev" "pylev.wfi_levenshtein('Levenshtein', 'Frankenstein')" +echo -ne "pypy damerau_levenshtein\t\t" +pypy -m timeit -s "import pylev" "pylev.damerau_levenshtein('Levenshtein', 'Frankenstein')" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylev-1.3.0/pylev/__init__.py new/pylev-1.4.0/pylev/__init__.py --- old/pylev-1.3.0/pylev/__init__.py 1970-01-01 01:00:00.000000000 +0100 +++ new/pylev-1.4.0/pylev/__init__.py 2021-05-30 22:04:52.000000000 +0200 @@ -0,0 +1,44 @@ +""" +pylev +===== + +A pure Python Levenshtein implementation that's not freaking GPL'd. + +Based off the Wikipedia code samples at +http://en.wikipedia.org/wiki/Levenshtein_distance. + +Usage +----- + +Usage is fairly straightforward.:: + + import pylev + distance = pylev.levenshtein('kitten', 'sitting') + assert distance == 3 + +""" +from .classic import classic_levenshtein +from .recursive import recursive_levenshtein +from .wf import wf_levenshtein, wfi_levenshtein +from .damerau import damerau_levenshtein + +__author__ = "Daniel Lindsley" +__version__ = (1, 4, 0) +__license__ = "New BSD" + + +levenshtein = wfi_levenshtein + +# Backward-compatibilty because I misspelled. +classic_levenschtein = classic_levenshtein +levenschtein = levenshtein + + +__all__ = [ + "levenshtein", + "classic_levenshtein", + "recursive_levenshtein", + "wf_levenshtein", + "wfi_levenshtein", + "damerau_levenshtein", +] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylev-1.3.0/pylev/classic.py new/pylev-1.4.0/pylev/classic.py --- old/pylev-1.3.0/pylev/classic.py 1970-01-01 01:00:00.000000000 +0100 +++ new/pylev-1.4.0/pylev/classic.py 2021-05-30 21:24:05.000000000 +0200 @@ -0,0 +1,35 @@ +def classic_levenshtein(string_1, string_2): + """ + Calculates the Levenshtein distance between two strings. + + This version is easier to read, but significantly slower than the version + below (up to several orders of magnitude). Useful for learning, less so + otherwise. + + Usage:: + + >>> classic_levenshtein('kitten', 'sitting') + 3 + >>> classic_levenshtein('kitten', 'kitten') + 0 + >>> classic_levenshtein('', '') + 0 + + """ + len_1 = len(string_1) + len_2 = len(string_2) + cost = 0 + + if len_1 and len_2 and string_1[0] != string_2[0]: + cost = 1 + + if len_1 == 0: + return len_2 + elif len_2 == 0: + return len_1 + else: + return min( + classic_levenshtein(string_1[1:], string_2) + 1, + classic_levenshtein(string_1, string_2[1:]) + 1, + classic_levenshtein(string_1[1:], string_2[1:]) + cost, + ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylev-1.3.0/pylev/damerau.py new/pylev-1.4.0/pylev/damerau.py --- old/pylev-1.3.0/pylev/damerau.py 1970-01-01 01:00:00.000000000 +0100 +++ new/pylev-1.4.0/pylev/damerau.py 2021-05-30 21:24:05.000000000 +0200 @@ -0,0 +1,80 @@ +import sys + + +PY2 = sys.version_info[0] == 2 + +if PY2: + range = xrange + + +def damerau_levenshtein(string_1, string_2): + """ + Calculates the Damerau-Levenshtein distance between two strings. + + In addition to insertions, deletions and substitutions, + Damerau-Levenshtein considers adjacent transpositions. + + This version is based on an iterative version of the Wagner-Fischer algorithm. + + Usage:: + + >>> damerau_levenshtein('kitten', 'sitting') + 3 + >>> damerau_levenshtein('kitten', 'kittne') + 1 + >>> damerau_levenshtein('', '') + 0 + + """ + if string_1 == string_2: + return 0 + + len_1 = len(string_1) + len_2 = len(string_2) + + if len_1 == 0: + return len_2 + if len_2 == 0: + return len_1 + + if len_1 > len_2: + string_2, string_1 = string_1, string_2 + len_2, len_1 = len_1, len_2 + + prev_cost = 0 + d0 = [i for i in range(len_2 + 1)] + d1 = [j for j in range(len_2 + 1)] + dprev = d0[:] + + s1 = string_1 + s2 = string_2 + + for i in range(len_1): + d1[0] = i + 1 + for j in range(len_2): + cost = d0[j] + + if s1[i] != s2[j]: + # substitution + cost += 1 + + # insertion + x_cost = d1[j] + 1 + if x_cost < cost: + cost = x_cost + + # deletion + y_cost = d0[j + 1] + 1 + if y_cost < cost: + cost = y_cost + + # transposition + if i > 0 and j > 0 and s1[i] == s2[j - 1] and s1[i - 1] == s2[j]: + transp_cost = dprev[j - 1] + 1 + if transp_cost < cost: + cost = transp_cost + d1[j + 1] = cost + + dprev, d0, d1 = d0, d1, dprev + + return d0[-1] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylev-1.3.0/pylev/recursive.py new/pylev-1.4.0/pylev/recursive.py --- old/pylev-1.3.0/pylev/recursive.py 1970-01-01 01:00:00.000000000 +0100 +++ new/pylev-1.4.0/pylev/recursive.py 2021-05-30 21:24:05.000000000 +0200 @@ -0,0 +1,56 @@ +def recursive_levenshtein( + string_1, string_2, len_1=None, len_2=None, offset_1=0, offset_2=0, memo=None +): + """ + Calculates the Levenshtein distance between two strings. + + Usage:: + + >>> recursive_levenshtein('kitten', 'sitting') + 3 + >>> recursive_levenshtein('kitten', 'kitten') + 0 + >>> recursive_levenshtein('', '') + 0 + + """ + if len_1 is None: + len_1 = len(string_1) + + if len_2 is None: + len_2 = len(string_2) + + if memo is None: + memo = {} + + key = ",".join([str(offset_1), str(len_1), str(offset_2), str(len_2)]) + + if memo.get(key) is not None: + return memo[key] + + if len_1 == 0: + return len_2 + elif len_2 == 0: + return len_1 + + cost = 0 + + if string_1[offset_1] != string_2[offset_2]: + cost = 1 + + dist = min( + recursive_levenshtein( + string_1, string_2, len_1 - 1, len_2, offset_1 + 1, offset_2, memo + ) + + 1, + recursive_levenshtein( + string_1, string_2, len_1, len_2 - 1, offset_1, offset_2 + 1, memo + ) + + 1, + recursive_levenshtein( + string_1, string_2, len_1 - 1, len_2 - 1, offset_1 + 1, offset_2 + 1, memo + ) + + cost, + ) + memo[key] = dist + return dist diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylev-1.3.0/pylev/wf.py new/pylev-1.4.0/pylev/wf.py --- old/pylev-1.3.0/pylev/wf.py 1970-01-01 01:00:00.000000000 +0100 +++ new/pylev-1.4.0/pylev/wf.py 2021-05-30 21:24:05.000000000 +0200 @@ -0,0 +1,107 @@ +import sys + + +PY2 = sys.version_info[0] == 2 + +if PY2: + range = xrange + + +def wf_levenshtein(string_1, string_2): + """ + Calculates the Levenshtein distance between two strings. + + This version uses the Wagner-Fischer algorithm. + + Usage:: + + >>> wf_levenshtein('kitten', 'sitting') + 3 + >>> wf_levenshtein('kitten', 'kitten') + 0 + >>> wf_levenshtein('', '') + 0 + + """ + len_1 = len(string_1) + 1 + len_2 = len(string_2) + 1 + + d = [0] * (len_1 * len_2) + + for i in range(len_1): + d[i] = i + for j in range(len_2): + d[j * len_1] = j + + for j in range(1, len_2): + for i in range(1, len_1): + if string_1[i - 1] == string_2[j - 1]: + d[i + j * len_1] = d[i - 1 + (j - 1) * len_1] + else: + d[i + j * len_1] = min( + d[i - 1 + j * len_1] + 1, # deletion + d[i + (j - 1) * len_1] + 1, # insertion + d[i - 1 + (j - 1) * len_1] + 1, # substitution + ) + + return d[-1] + + +def wfi_levenshtein(string_1, string_2): + """ + Calculates the Levenshtein distance between two strings. + + This version uses an iterative version of the Wagner-Fischer algorithm. + + Usage:: + + >>> wfi_levenshtein('kitten', 'sitting') + 3 + >>> wfi_levenshtein('kitten', 'kitten') + 0 + >>> wfi_levenshtein('', '') + 0 + + """ + if string_1 == string_2: + return 0 + + len_1 = len(string_1) + len_2 = len(string_2) + + if len_1 == 0: + return len_2 + if len_2 == 0: + return len_1 + + if len_1 > len_2: + string_2, string_1 = string_1, string_2 + len_2, len_1 = len_1, len_2 + + d0 = [i for i in range(len_2 + 1)] + d1 = [j for j in range(len_2 + 1)] + + for i in range(len_1): + d1[0] = i + 1 + for j in range(len_2): + cost = d0[j] + + if string_1[i] != string_2[j]: + # substitution + cost += 1 + + # insertion + x_cost = d1[j] + 1 + if x_cost < cost: + cost = x_cost + + # deletion + y_cost = d0[j + 1] + 1 + if y_cost < cost: + cost = y_cost + + d1[j + 1] = cost + + d0, d1 = d1, d0 + + return d0[-1] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylev-1.3.0/pylev.egg-info/PKG-INFO new/pylev-1.4.0/pylev.egg-info/PKG-INFO --- old/pylev-1.3.0/pylev.egg-info/PKG-INFO 2014-10-23 02:24:16.000000000 +0200 +++ new/pylev-1.4.0/pylev.egg-info/PKG-INFO 2021-05-30 22:05:22.000000000 +0200 @@ -1,87 +1,11 @@ -Metadata-Version: 1.1 +Metadata-Version: 2.1 Name: pylev -Version: 1.3.0 +Version: 1.4.0 Summary: A pure Python Levenshtein implementation that's not freaking GPL'd. Home-page: http://github.com/toastdriven/pylev Author: Daniel Lindsley Author-email: dan...@toastdriven.com License: UNKNOWN -Description: pylev - ===== - - A pure Python Levenshtein implementation that's not freaking GPL'd. - - Based off the Wikipedia code samples at - http://en.wikipedia.org/wiki/Levenshtein_distance. - - - Requirements - ------------ - - * Python 2.7.X, Python 3.3+ or PyPy 1.6.0+ - - - Usage - ----- - - Usage is fairly straightforward.:: - - import pylev - distance = pylev.levenshtein('kitten', 'sitting') - assert(distance, 3) - - - License - ------- - - New BSD. - - - Tests - ----- - - Setup:: - - $ git clone https://github.com/toastdriven/pylev.git - $ cd pylev - - Running:: - - $ python -m unittest tests - - [](https://travis-ci.org/toastdriven/pylev) - - - Version History - --------------- - - * v1.3.0 - - * Implemented a considerably faster variants (orders of magnitude). - * Tested & working on Python 2.7.4, Python 3.3.1 & PyPy 1.9.0. - - * v1.2.0 - - * Fixed all incorrect spellings of "Levenshtein" (there's no "c" in it). - * Old methods are aliased for backward-compatibility. - - * v1.1.0 - - * Implemented a much faster variant (several orders of magnitude). - * The older variant was renamed to ``classic_levenschtein``. - * Tested & working on Python 3.3 & PyPy 1.6.0 as well. - - * v1.0.2 - - * Python packaging is **REALLY** hard. Including the README *this time*. - - * v1.0.1 - - * Python packaging is hard. Including the README this time. - - * v1.0.0 - - * Initial release, just the naive implementation of Levenshtein. Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers @@ -89,3 +13,94 @@ Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 +License-File: LICENSE + +pylev +===== + +A pure Python Levenshtein implementation that's not freaking GPL'd. + +Based off the Wikipedia code samples at +http://en.wikipedia.org/wiki/Levenshtein_distance. + + +Requirements +------------ + +* Python 2.7.X, Python 3.3+ or PyPy 1.6.0+ + + +Usage +----- + +Usage is fairly straightforward: + +.. code-block:: python + + import pylev + distance = pylev.levenshtein('kitten', 'sitting') + assert distance == 3 + + +License +------- + +New BSD. + + +Tests +----- + +Setup:: + + $ git clone https://github.com/toastdriven/pylev.git + $ cd pylev + +Running:: + + $ python -m unittest tests + +.. image:: https://travis-ci.com/toastdriven/pylev.svg?branch=main + :target: http://travis-ci.com/toastdriven/pylev + + +Version History +--------------- + +* v1.4.0 + + * Updated for current versions of Python + * Integrated a better Travis matrix. Thanks to @grainert! + * Fixed mistaken docs about the `assert`. Thanks to @adamchainz! + * Reorganized the package. + * Blacked all the source code. + +* v1.3.0 + + * Implemented a considerably faster variants (orders of magnitude). + * Tested & working on Python 2.7.4, Python 3.3.1 & PyPy 1.9.0. + +* v1.2.0 + + * Fixed all incorrect spellings of "Levenshtein" (there's no "c" in it). + * Old methods are aliased for backward-compatibility. + +* v1.1.0 + + * Implemented a much faster variant (several orders of magnitude). + * The older variant was renamed to ``classic_levenschtein``. + * Tested & working on Python 3.3 & PyPy 1.6.0 as well. + +* v1.0.2 + + * Python packaging is **REALLY** hard. Including the README *this time*. + +* v1.0.1 + + * Python packaging is hard. Including the README this time. + +* v1.0.0 + + * Initial release, just the naive implementation of Levenshtein. + + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylev-1.3.0/pylev.egg-info/SOURCES.txt new/pylev-1.4.0/pylev.egg-info/SOURCES.txt --- old/pylev-1.3.0/pylev.egg-info/SOURCES.txt 2014-10-23 02:24:16.000000000 +0200 +++ new/pylev-1.4.0/pylev.egg-info/SOURCES.txt 2021-05-30 22:05:22.000000000 +0200 @@ -1,8 +1,17 @@ +LICENSE +MANIFEST.in README.rst -pylev.py +bench.sh +pyproject.toml setup.cfg setup.py +pylev/__init__.py +pylev/classic.py +pylev/damerau.py +pylev/recursive.py +pylev/wf.py pylev.egg-info/PKG-INFO pylev.egg-info/SOURCES.txt pylev.egg-info/dependency_links.txt +pylev.egg-info/not-zip-safe pylev.egg-info/top_level.txt \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylev-1.3.0/pylev.egg-info/not-zip-safe new/pylev-1.4.0/pylev.egg-info/not-zip-safe --- old/pylev-1.3.0/pylev.egg-info/not-zip-safe 1970-01-01 01:00:00.000000000 +0100 +++ new/pylev-1.4.0/pylev.egg-info/not-zip-safe 2021-05-30 22:05:22.000000000 +0200 @@ -0,0 +1 @@ + diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylev-1.3.0/pylev.py new/pylev-1.4.0/pylev.py --- old/pylev-1.3.0/pylev.py 2014-10-23 02:24:01.000000000 +0200 +++ new/pylev-1.4.0/pylev.py 1970-01-01 01:00:00.000000000 +0100 @@ -1,293 +0,0 @@ -""" -pylev -===== - -A pure Python Levenshtein implementation that's not freaking GPL'd. - -Based off the Wikipedia code samples at -http://en.wikipedia.org/wiki/Levenshtein_distance. - -Usage ------ - -Usage is fairly straightforward.:: - - import pylev - distance = pylev.levenshtein('kitten', 'sitting') - assert(distance, 3) - -""" -__author__ = 'Daniel Lindsley' -__version__ = (1, 3, 0) -__license__ = 'New BSD' - - -import sys -PY2 = sys.version_info[0] == 2 - -if PY2: - range = xrange - - -def classic_levenshtein(string_1, string_2): - """ - Calculates the Levenshtein distance between two strings. - - This version is easier to read, but significantly slower than the version - below (up to several orders of magnitude). Useful for learning, less so - otherwise. - - Usage:: - - >>> classic_levenshtein('kitten', 'sitting') - 3 - >>> classic_levenshtein('kitten', 'kitten') - 0 - >>> classic_levenshtein('', '') - 0 - - """ - len_1 = len(string_1) - len_2 = len(string_2) - cost = 0 - - if len_1 and len_2 and string_1[0] != string_2[0]: - cost = 1 - - if len_1 == 0: - return len_2 - elif len_2 == 0: - return len_1 - else: - return min( - classic_levenshtein(string_1[1:], string_2) + 1, - classic_levenshtein(string_1, string_2[1:]) + 1, - classic_levenshtein(string_1[1:], string_2[1:]) + cost, - ) - - -def recursive_levenshtein(string_1, string_2, len_1=None, len_2=None, offset_1=0, offset_2=0, memo=None): - """ - Calculates the Levenshtein distance between two strings. - - Usage:: - - >>> recursive_levenshtein('kitten', 'sitting') - 3 - >>> recursive_levenshtein('kitten', 'kitten') - 0 - >>> recursive_levenshtein('', '') - 0 - - """ - if len_1 is None: - len_1 = len(string_1) - - if len_2 is None: - len_2 = len(string_2) - - if memo is None: - memo = {} - - key = ','.join([str(offset_1), str(len_1), str(offset_2), str(len_2)]) - - if memo.get(key) is not None: - return memo[key] - - if len_1 == 0: - return len_2 - elif len_2 == 0: - return len_1 - - cost = 0 - - if string_1[offset_1] != string_2[offset_2]: - cost = 1 - - dist = min( - recursive_levenshtein(string_1, string_2, len_1 - 1, len_2, offset_1 + 1, offset_2, memo) + 1, - recursive_levenshtein(string_1, string_2, len_1, len_2 - 1, offset_1, offset_2 + 1, memo) + 1, - recursive_levenshtein(string_1, string_2, len_1 - 1, len_2 - 1, offset_1 + 1, offset_2 + 1, memo) + cost, - ) - memo[key] = dist - return dist - - -def wf_levenshtein(string_1, string_2): - """ - Calculates the Levenshtein distance between two strings. - - This version uses the Wagner-Fischer algorithm. - - Usage:: - - >>> wf_levenshtein('kitten', 'sitting') - 3 - >>> wf_levenshtein('kitten', 'kitten') - 0 - >>> wf_levenshtein('', '') - 0 - - """ - len_1 = len(string_1) + 1 - len_2 = len(string_2) + 1 - - d = [0] * (len_1 * len_2) - - for i in range(len_1): - d[i] = i - for j in range(len_2): - d[j * len_1] = j - - for j in range(1, len_2): - for i in range(1, len_1): - if string_1[i - 1] == string_2[j - 1]: - d[i + j * len_1] = d[i - 1 + (j - 1) * len_1] - else: - d[i + j * len_1] = min( - d[i - 1 + j * len_1] + 1, # deletion - d[i + (j - 1) * len_1] + 1, # insertion - d[i - 1 + (j - 1) * len_1] + 1, # substitution - ) - - return d[-1] - - -def wfi_levenshtein(string_1, string_2): - """ - Calculates the Levenshtein distance between two strings. - - This version uses an iterative version of the Wagner-Fischer algorithm. - - Usage:: - - >>> wfi_levenshtein('kitten', 'sitting') - 3 - >>> wfi_levenshtein('kitten', 'kitten') - 0 - >>> wfi_levenshtein('', '') - 0 - - """ - if string_1 == string_2: - return 0 - - len_1 = len(string_1) - len_2 = len(string_2) - - if len_1 == 0: - return len_2 - if len_2 == 0: - return len_1 - - if len_1 > len_2: - string_2, string_1 = string_1, string_2 - len_2, len_1 = len_1, len_2 - - d0 = [i for i in range(len_2 + 1)] - d1 = [j for j in range(len_2 + 1)] - - for i in range(len_1): - d1[0] = i + 1 - for j in range(len_2): - cost = d0[j] - - if string_1[i] != string_2[j]: - # substitution - cost += 1 - - # insertion - x_cost = d1[j] + 1 - if x_cost < cost: - cost = x_cost - - # deletion - y_cost = d0[j + 1] + 1 - if y_cost < cost: - cost = y_cost - - d1[j + 1] = cost - - d0, d1 = d1, d0 - - return d0[-1] - - -def damerau_levenshtein(string_1, string_2): - """ - Calculates the Damerau-Levenshtein distance between two strings. - - In addition to insertions, deletions and substitutions, - Damerau-Levenshtein considers adjacent transpositions. - - This version is based on an iterative version of the Wagner-Fischer algorithm. - - Usage:: - - >>> damerau_levenshtein('kitten', 'sitting') - 3 - >>> damerau_levenshtein('kitten', 'kittne') - 1 - >>> damerau_levenshtein('', '') - 0 - - """ - if string_1 == string_2: - return 0 - - len_1 = len(string_1) - len_2 = len(string_2) - - if len_1 == 0: - return len_2 - if len_2 == 0: - return len_1 - - if len_1 > len_2: - string_2, string_1 = string_1, string_2 - len_2, len_1 = len_1, len_2 - - prev_cost = 0 - d0 = [i for i in range(len_2 + 1)] - d1 = [j for j in range(len_2 + 1)] - dprev = d0[:] - - s1 = string_1 - s2 = string_2 - - for i in range(len_1): - d1[0] = i + 1 - for j in range(len_2): - cost = d0[j] - - if s1[i] != s2[j]: - # substitution - cost += 1 - - # insertion - x_cost = d1[j] + 1 - if x_cost < cost: - cost = x_cost - - # deletion - y_cost = d0[j + 1] + 1 - if y_cost < cost: - cost = y_cost - - # transposition - if i > 0 and j > 0 and s1[i] == s2[j - 1] and s1[i - 1] == s2[j]: - transp_cost = dprev[j - 1] + 1 - if transp_cost < cost: - cost = transp_cost - d1[j + 1] = cost - - dprev, d0, d1 = d0, d1, dprev - - return d0[-1] - - -levenshtein = wfi_levenshtein - -# Backward-compatibilty because I misspelled. -classic_levenschtein = classic_levenshtein -levenschtein = levenshtein diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylev-1.3.0/pyproject.toml new/pylev-1.4.0/pyproject.toml --- old/pylev-1.3.0/pyproject.toml 1970-01-01 01:00:00.000000000 +0100 +++ new/pylev-1.4.0/pyproject.toml 2021-05-30 22:04:52.000000000 +0200 @@ -0,0 +1,6 @@ +[build-system] +requires = [ + "setuptools>=42", + "wheel" +] +build-backend = "setuptools.build_meta" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylev-1.3.0/setup.cfg new/pylev-1.4.0/setup.cfg --- old/pylev-1.3.0/setup.cfg 2014-10-23 02:24:16.000000000 +0200 +++ new/pylev-1.4.0/setup.cfg 2021-05-30 22:05:22.000000000 +0200 @@ -4,5 +4,4 @@ [egg_info] tag_build = tag_date = 0 -tag_svn_revision = 0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pylev-1.3.0/setup.py new/pylev-1.4.0/setup.py --- old/pylev-1.3.0/setup.py 2014-10-23 02:24:01.000000000 +0200 +++ new/pylev-1.4.0/setup.py 2021-05-30 22:04:52.000000000 +0200 @@ -5,22 +5,27 @@ except ImportError: from distutils.core import setup + setup( - name='pylev', - version='1.3.0', + name="pylev", + version="1.4.0", description="A pure Python Levenshtein implementation that's not freaking GPL'd.", - author='Daniel Lindsley', - author_email='dan...@toastdriven.com', - long_description=open(os.path.join(os.path.dirname(__file__), 'README.rst'), 'r').read(), - py_modules=['pylev'], + author="Daniel Lindsley", + author_email="dan...@toastdriven.com", + long_description=open( + os.path.join(os.path.dirname(__file__), "README.rst"), "r" + ).read(), + packages=["pylev"], + include_package_data=True, + zip_safe=False, classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: BSD License', - 'Operating System :: OS Independent', - 'Programming Language :: Python', + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Programming Language :: Python", # That's right, works in Py3 (& PyPy) too! "Programming Language :: Python :: 3", ], - url='http://github.com/toastdriven/pylev' + url="http://github.com/toastdriven/pylev", ) ++++++ tests.py ++++++ --- /var/tmp/diff_new_pack.Ul8c2S/_old 2022-10-08 01:25:36.626282698 +0200 +++ /var/tmp/diff_new_pack.Ul8c2S/_new 2022-10-08 01:25:36.630282707 +0200 @@ -2,25 +2,26 @@ import unittest import pylev + test_data = [ - ('classic', "kitten", "sitting", 3), - ('same', "kitten", "kitten", 0), - ('empty', "", "", 0), - ('a', "meilenstein", "levenshtein", 4), - ('b', "levenshtein", "frankenstein", 6), - ('c', "confide", "deceit", 6), - ('d', "CUNsperrICY", "conspiracy", 8), + ("classic", "kitten", "sitting", 3), + ("same", "kitten", "kitten", 0), + ("empty", "", "", 0), + ("a", "meilenstein", "levenshtein", 4), + ("b", "levenshtein", "frankenstein", 6), + ("c", "confide", "deceit", 6), + ("d", "CUNsperrICY", "conspiracy", 8), ] test_functions = [ # pylev.classic_levenshtein, # disabled because it is so slow pylev.recursive_levenshtein, pylev.wf_levenshtein, - pylev.wfi_levenshtein + pylev.wfi_levenshtein, ] -class Tests(unittest.TestCase): +class Tests(unittest.TestCase): def test_damerau_levenshtein(seld): assert pylev.damerau_levenshtein("ba", "abc") == 2 assert pylev.damerau_levenshtein("foobar", "foobra") == 1 @@ -41,6 +42,6 @@ setattr(Tests, "test_%s_%s" % (name, lev_fn.__name__), test_fn) -if __name__ == '__main__': +if __name__ == "__main__": unittest.main()